GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* |
||
2 |
* The ManaPlus Client |
||
3 |
* Copyright (C) 2008 The Legend of Mazzeroth Development Team |
||
4 |
* Copyright (C) 2009 Aethyra Development Team |
||
5 |
* Copyright (C) 2009 The Mana World Development Team |
||
6 |
* Copyright (C) 2009-2010 The Mana Developers |
||
7 |
* Copyright (C) 2011-2019 The ManaPlus Developers |
||
8 |
* Copyright (C) 2019-2021 Andrei Karas |
||
9 |
* |
||
10 |
* This file is part of The ManaPlus Client. |
||
11 |
* |
||
12 |
* This program is free software; you can redistribute it and/or modify |
||
13 |
* it under the terms of the GNU General Public License as published by |
||
14 |
* the Free Software Foundation; either version 2 of the License, or |
||
15 |
* any later version. |
||
16 |
* |
||
17 |
* This program is distributed in the hope that it will be useful, |
||
18 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
19 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
20 |
* GNU General Public License for more details. |
||
21 |
* |
||
22 |
* You should have received a copy of the GNU General Public License |
||
23 |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||
24 |
*/ |
||
25 |
|||
26 |
#include "gui/theme.h" |
||
27 |
|||
28 |
#include "configuration.h" |
||
29 |
#include "graphicsmanager.h" |
||
30 |
|||
31 |
#include "const/gui/theme.h" |
||
32 |
|||
33 |
#include "fs/virtfs/fs.h" |
||
34 |
#include "fs/virtfs/list.h" |
||
35 |
|||
36 |
#include "gui/skin.h" |
||
37 |
#include "gui/themeinfo.h" |
||
38 |
|||
39 |
#include "resources/imagerect.h" |
||
40 |
|||
41 |
#include "resources/dye/dyepalette.h" |
||
42 |
|||
43 |
#include "resources/image/image.h" |
||
44 |
|||
45 |
#include "resources/loaders/imageloader.h" |
||
46 |
#include "resources/loaders/imagesetloader.h" |
||
47 |
#include "resources/loaders/subimageloader.h" |
||
48 |
#include "resources/loaders/subimagesetloader.h" |
||
49 |
#include "resources/loaders/xmlloader.h" |
||
50 |
|||
51 |
#include "utils/dtor.h" |
||
52 |
#include "utils/foreach.h" |
||
53 |
|||
54 |
#include "debug.h" |
||
55 |
|||
56 |
1 |
static std::string defaultThemePath; |
|
57 |
|||
58 |
1 |
std::string Theme::mThemePath; |
|
59 |
1 |
std::string Theme::mThemeName; |
|
60 |
1 |
std::string Theme::mScreenDensity; |
|
61 |
|||
62 |
Theme *theme = nullptr; |
||
63 |
|||
64 |
// Set the theme path... |
||
65 |
454 |
static void initDefaultThemePath() |
|
66 |
{ |
||
67 |
✓✗ | 2270 |
defaultThemePath = branding.getStringValue("guiThemePath"); |
68 |
|||
69 |
✓✗ | 908 |
logger->log("defaultThemePath: " + defaultThemePath); |
70 |
✓✗✗✓ ✗✓ |
1816 |
if (!defaultThemePath.empty() && |
71 |
✓✗✗✓ ✗✗ |
1362 |
VirtFs::isDirectory(defaultThemePath)) |
72 |
{ |
||
73 |
return; |
||
74 |
} |
||
75 |
defaultThemePath = "themes/"; |
||
76 |
} |
||
77 |
|||
78 |
227 |
Theme::Theme() : |
|
79 |
Palette(CAST_S32(ThemeColorId::THEME_COLORS_END) * THEME_PALETTES), |
||
80 |
mSkins(), |
||
81 |
mMinimumOpacity(-1.0F), |
||
82 |
mProgressColors(ProgressColors(CAST_SIZE( |
||
83 |
✓✗ | 1135 |
ProgressColorId::THEME_PROG_END))) |
84 |
{ |
||
85 |
✓✗ | 227 |
initDefaultThemePath(); |
86 |
|||
87 |
✓✗✓✗ |
908 |
config.addListener("guialpha", this); |
88 |
|||
89 |
227 |
mColors[CAST_SIZE(ThemeColorId::HIGHLIGHT)].ch = 'H'; |
|
90 |
227 |
mColors[CAST_SIZE(ThemeColorId::CHAT)].ch = 'C'; |
|
91 |
227 |
mColors[CAST_SIZE(ThemeColorId::GM)].ch = 'G'; |
|
92 |
227 |
mColors[CAST_SIZE(ThemeColorId::GLOBAL)].ch = 'g'; |
|
93 |
227 |
mColors[CAST_SIZE(ThemeColorId::PLAYER)].ch = 'Y'; |
|
94 |
227 |
mColors[CAST_SIZE(ThemeColorId::WHISPER_TAB)].ch = 'W'; |
|
95 |
227 |
mColors[CAST_SIZE(ThemeColorId::WHISPER_TAB_OFFLINE)].ch = 'w'; |
|
96 |
227 |
mColors[CAST_SIZE(ThemeColorId::IS)].ch = 'I'; |
|
97 |
227 |
mColors[CAST_SIZE(ThemeColorId::PARTY_CHAT_TAB)].ch = 'P'; |
|
98 |
227 |
mColors[CAST_SIZE(ThemeColorId::GUILD_CHAT_TAB)].ch = 'U'; |
|
99 |
227 |
mColors[CAST_SIZE(ThemeColorId::SERVER)].ch = 'S'; |
|
100 |
227 |
mColors[CAST_SIZE(ThemeColorId::LOGGER)].ch = 'L'; |
|
101 |
227 |
mColors[CAST_SIZE(ThemeColorId::HYPERLINK)].ch = '<'; |
|
102 |
227 |
mColors[CAST_SIZE(ThemeColorId::SELFNICK)].ch = 's'; |
|
103 |
227 |
mColors[CAST_SIZE(ThemeColorId::OLDCHAT)].ch = 'o'; |
|
104 |
227 |
mColors[CAST_SIZE(ThemeColorId::AWAYCHAT)].ch = 'a'; |
|
105 |
✓✗ | 227 |
mCharColors['H'] = CAST_S32(ThemeColorId::HIGHLIGHT); |
106 |
✓✗ | 227 |
mCharColors['C'] = CAST_S32(ThemeColorId::CHAT); |
107 |
✓✗ | 227 |
mCharColors['G'] = CAST_S32(ThemeColorId::GM); |
108 |
✓✗ | 227 |
mCharColors['g'] = CAST_S32(ThemeColorId::GLOBAL); |
109 |
✓✗ | 227 |
mCharColors['Y'] = CAST_S32(ThemeColorId::PLAYER); |
110 |
✓✗ | 227 |
mCharColors['W'] = CAST_S32(ThemeColorId::WHISPER_TAB); |
111 |
✓✗ | 227 |
mCharColors['w'] = CAST_S32(ThemeColorId::WHISPER_TAB_OFFLINE); |
112 |
✓✗ | 227 |
mCharColors['I'] = CAST_S32(ThemeColorId::IS); |
113 |
✓✗ | 227 |
mCharColors['P'] = CAST_S32(ThemeColorId::PARTY_CHAT_TAB); |
114 |
✓✗ | 227 |
mCharColors['U'] = CAST_S32(ThemeColorId::GUILD_CHAT_TAB); |
115 |
✓✗ | 227 |
mCharColors['S'] = CAST_S32(ThemeColorId::SERVER); |
116 |
✓✗ | 227 |
mCharColors['L'] = CAST_S32(ThemeColorId::LOGGER); |
117 |
✓✗ | 227 |
mCharColors['<'] = CAST_S32(ThemeColorId::HYPERLINK); |
118 |
✓✗ | 227 |
mCharColors['s'] = CAST_S32(ThemeColorId::SELFNICK); |
119 |
✓✗ | 227 |
mCharColors['o'] = CAST_S32(ThemeColorId::OLDCHAT); |
120 |
✓✗ | 227 |
mCharColors['a'] = CAST_S32(ThemeColorId::AWAYCHAT); |
121 |
|||
122 |
// here need use outlined colors |
||
123 |
✓✗ | 454 |
mCharColors['H' | 0x80] |
124 |
227 |
= CAST_S32(ThemeColorId::HIGHLIGHT_OUTLINE); |
|
125 |
✓✗ | 227 |
mCharColors['C' | 0x80] = CAST_S32(ThemeColorId::CHAT_OUTLINE); |
126 |
✓✗ | 227 |
mCharColors['G' | 0x80] = CAST_S32(ThemeColorId::GM_OUTLINE); |
127 |
✓✗ | 227 |
mCharColors['g' | 0x80] = CAST_S32(ThemeColorId::GLOBAL_OUTLINE); |
128 |
✓✗ | 227 |
mCharColors['Y' | 0x80] = CAST_S32(ThemeColorId::PLAYER_OUTLINE); |
129 |
✓✗ | 454 |
mCharColors['W' | 0x80] |
130 |
227 |
= CAST_S32(ThemeColorId::WHISPER_TAB_OUTLINE); |
|
131 |
✓✗ | 454 |
mCharColors['w' | 0x80] |
132 |
227 |
= CAST_S32(ThemeColorId::WHISPER_TAB_OFFLINE_OUTLINE); |
|
133 |
✓✗ | 227 |
mCharColors['I' | 0x80] = CAST_S32(ThemeColorId::IS_OUTLINE); |
134 |
✓✗ | 454 |
mCharColors['P' | 0x80] |
135 |
227 |
= CAST_S32(ThemeColorId::PARTY_CHAT_TAB_OUTLINE); |
|
136 |
✓✗ | 454 |
mCharColors['U' | 0x80] |
137 |
227 |
= CAST_S32(ThemeColorId::GUILD_CHAT_TAB_OUTLINE); |
|
138 |
✓✗ | 227 |
mCharColors['S' | 0x80] = CAST_S32(ThemeColorId::SERVER_OUTLINE); |
139 |
✓✗ | 227 |
mCharColors['L' | 0x80] = CAST_S32(ThemeColorId::LOGGER_OUTLINE); |
140 |
✓✗ | 454 |
mCharColors['<' | 0x80] |
141 |
227 |
= CAST_S32(ThemeColorId::HYPERLINK_OUTLINE); |
|
142 |
✓✗ | 227 |
mCharColors['s' | 0x80] = CAST_S32(ThemeColorId::SELFNICK_OUTLINE); |
143 |
✓✗ | 227 |
mCharColors['o' | 0x80] = CAST_S32(ThemeColorId::OLDCHAT_OUTLINE); |
144 |
✓✗ | 227 |
mCharColors['a' | 0x80] = CAST_S32(ThemeColorId::AWAYCHAT_OUTLINE); |
145 |
227 |
} |
|
146 |
|||
147 |
1284 |
Theme::~Theme() |
|
148 |
{ |
||
149 |
428 |
delete_all(mSkins); |
|
150 |
856 |
config.removeListener("guialpha", this); |
|
151 |
CHECKLISTENERS |
||
152 |
428 |
delete_all(mProgressColors); |
|
153 |
428 |
} |
|
154 |
|||
155 |
24 |
Color Theme::getProgressColor(const ProgressColorIdT type, |
|
156 |
const float progress) |
||
157 |
{ |
||
158 |
24 |
int color[3] = {0, 0, 0}; |
|
159 |
|||
160 |
✓✗ | 24 |
if (theme != nullptr) |
161 |
{ |
||
162 |
const DyePalette *const dye |
||
163 |
48 |
= theme->mProgressColors[CAST_SIZE(type)]; |
|
164 |
|||
165 |
✓✗ | 24 |
if (dye != nullptr) |
166 |
{ |
||
167 |
24 |
dye->getColor(progress, color); |
|
168 |
} |
||
169 |
else |
||
170 |
{ |
||
171 |
logger->log("color not found: " |
||
172 |
+ toString(CAST_S32(type))); |
||
173 |
} |
||
174 |
} |
||
175 |
|||
176 |
24 |
return Color(color[0], color[1], color[2], 255U); |
|
177 |
} |
||
178 |
|||
179 |
2232 |
Skin *Theme::load(const std::string &filename, |
|
180 |
const std::string &filename2, |
||
181 |
const bool full, |
||
182 |
const std::string &restrict defaultPath) |
||
183 |
{ |
||
184 |
// Check if this skin was already loaded |
||
185 |
|||
186 |
4464 |
const SkinIterator skinIterator = mSkins.find(filename); |
|
187 |
✓✓ | 4464 |
if (mSkins.end() != skinIterator) |
188 |
{ |
||
189 |
✓✗ | 1394 |
if (skinIterator->second != nullptr) |
190 |
1394 |
skinIterator->second->instances++; |
|
191 |
return skinIterator->second; |
||
192 |
} |
||
193 |
|||
194 |
838 |
Skin *skin = nullptr; |
|
195 |
✓✗ | 838 |
if (mScreenDensity.empty()) |
196 |
{ // if no density detected |
||
197 |
838 |
skin = readSkin(filename, full); |
|
198 |
✓✓✓✗ ✗✓✓✓ |
1016 |
if ((skin == nullptr) && !filename2.empty() && filename2 != filename) |
199 |
89 |
skin = readSkin(filename2, full); |
|
200 |
✓✓✗✓ ✓✓ |
839 |
if ((skin == nullptr) && filename2 != "window.xml") |
201 |
✓✗ | 4 |
skin = readSkin("window.xml", full); |
202 |
} |
||
203 |
else |
||
204 |
{ // first use correct density images |
||
205 |
const std::string endStr("_" + mScreenDensity + ".xml"); |
||
206 |
std::string name = filename; |
||
207 |
if (findCutLast(name, ".xml")) |
||
208 |
skin = readSkin(name + endStr, full); |
||
209 |
if (skin == nullptr) |
||
210 |
skin = readSkin(filename, full); |
||
211 |
if ((skin == nullptr) && !filename2.empty() && filename2 != filename) |
||
212 |
{ |
||
213 |
name = filename2; |
||
214 |
if (findCutLast(name, ".xml")) |
||
215 |
skin = readSkin(name + endStr, full); |
||
216 |
if (skin == nullptr) |
||
217 |
skin = readSkin(filename2, full); |
||
218 |
} |
||
219 |
if ((skin == nullptr) && filename2 != "window.xml") |
||
220 |
{ |
||
221 |
skin = readSkin("window" + endStr, full); |
||
222 |
if (skin == nullptr) |
||
223 |
skin = readSkin("window.xml", full); |
||
224 |
} |
||
225 |
} |
||
226 |
|||
227 |
✗✓ | 838 |
if (skin == nullptr) |
228 |
{ |
||
229 |
// Try falling back on the defaultPath if this makes sense |
||
230 |
if (filename != defaultPath) |
||
231 |
{ |
||
232 |
logger->log("Error loading skin '%s', falling back on default.", |
||
233 |
filename.c_str()); |
||
234 |
|||
235 |
skin = readSkin(defaultPath, full); |
||
236 |
} |
||
237 |
|||
238 |
if (skin == nullptr) |
||
239 |
{ |
||
240 |
logger->log(strprintf("Error: Loading default skin '%s' failed. " |
||
241 |
"Make sure the skin file is valid.", |
||
242 |
defaultPath.c_str())); |
||
243 |
} |
||
244 |
} |
||
245 |
|||
246 |
838 |
mSkins[filename] = skin; |
|
247 |
838 |
return skin; |
|
248 |
} |
||
249 |
|||
250 |
2210 |
void Theme::unload(Skin *const skin) |
|
251 |
{ |
||
252 |
✓✗ | 2210 |
if (skin == nullptr) |
253 |
return; |
||
254 |
2210 |
skin->instances --; |
|
255 |
✓✓ | 2210 |
if (skin->instances == 0) |
256 |
{ |
||
257 |
1664 |
SkinIterator it = mSkins.begin(); |
|
258 |
1664 |
const SkinIterator it_end = mSkins.end(); |
|
259 |
✓✗ | 3332 |
while (it != it_end) |
260 |
{ |
||
261 |
✓✓ | 3332 |
if (it->second == skin) |
262 |
{ |
||
263 |
832 |
mSkins.erase(it); |
|
264 |
break; |
||
265 |
} |
||
266 |
++ it; |
||
267 |
} |
||
268 |
832 |
delete skin; |
|
269 |
} |
||
270 |
} |
||
271 |
|||
272 |
void Theme::setMinimumOpacity(const float minimumOpacity) |
||
273 |
{ |
||
274 |
if (minimumOpacity > 1.0F) |
||
275 |
return; |
||
276 |
|||
277 |
mMinimumOpacity = minimumOpacity; |
||
278 |
updateAlpha(); |
||
279 |
} |
||
280 |
|||
281 |
2873 |
void Theme::updateAlpha() |
|
282 |
{ |
||
283 |
✗✓ | 8619 |
FOR_EACH (SkinIterator, iter, mSkins) |
284 |
{ |
||
285 |
Skin *const skin = iter->second; |
||
286 |
if (skin != nullptr) |
||
287 |
skin->updateAlpha(mMinimumOpacity); |
||
288 |
} |
||
289 |
2873 |
} |
|
290 |
|||
291 |
2873 |
void Theme::optionChanged(const std::string &name A_UNUSED) |
|
292 |
{ |
||
293 |
2873 |
updateAlpha(); |
|
294 |
2873 |
} |
|
295 |
|||
296 |
78 |
struct SkinParameter final |
|
297 |
{ |
||
298 |
A_DEFAULT_COPY(SkinParameter) |
||
299 |
int index; |
||
300 |
std::string name; |
||
301 |
}; |
||
302 |
|||
303 |
✓✓ | 3 |
static const SkinParameter skinParam[] = |
304 |
{ |
||
305 |
{0, "top-left-corner"}, |
||
306 |
{0, "standart"}, |
||
307 |
{0, "up"}, |
||
308 |
{0, "hstart"}, |
||
309 |
{0, "in"}, |
||
310 |
{0, "normal"}, |
||
311 |
{1, "top-edge"}, |
||
312 |
{1, "highlighted"}, |
||
313 |
{1, "down"}, |
||
314 |
{1, "hmiddle"}, |
||
315 |
{1, "in-highlighted"}, |
||
316 |
{1, "checked"}, |
||
317 |
{2, "top-right-corner"}, |
||
318 |
{2, "pressed"}, |
||
319 |
{2, "left"}, |
||
320 |
{2, "hend"}, |
||
321 |
{2, "out"}, |
||
322 |
{2, "disabled"}, |
||
323 |
{3, "left-edge"}, |
||
324 |
{3, "disabled"}, |
||
325 |
{3, "right"}, |
||
326 |
{3, "hgrip"}, |
||
327 |
{3, "out-highlighted"}, |
||
328 |
{3, "disabled-checked"}, |
||
329 |
{4, "bg-quad"}, |
||
330 |
{4, "vstart"}, |
||
331 |
{4, "normal-highlighted"}, |
||
332 |
{5, "right-edge"}, |
||
333 |
{5, "vmiddle"}, |
||
334 |
{5, "checked-highlighted"}, |
||
335 |
{6, "bottom-left-corner"}, |
||
336 |
{6, "vend"}, |
||
337 |
{7, "bottom-edge"}, |
||
338 |
{7, "vgrip"}, |
||
339 |
{8, "bottom-right-corner"}, |
||
340 |
✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✗✗ |
71 |
}; |
341 |
|||
342 |
✓✓ | 3 |
static const SkinParameter imageParam[] = |
343 |
{ |
||
344 |
{0, "closeImage"}, |
||
345 |
{1, "closeImageHighlighted"}, |
||
346 |
{2, "stickyImageUp"}, |
||
347 |
{3, "stickyImageDown"}, |
||
348 |
✓✗✓✗ ✓✗✓✗ ✗✗ |
9 |
}; |
349 |
|||
350 |
1676 |
struct SkinHelper final |
|
351 |
{ |
||
352 |
838 |
SkinHelper() : |
|
353 |
partType(), |
||
354 |
xPos(), |
||
355 |
yPos(), |
||
356 |
width(), |
||
357 |
height(), |
||
358 |
rect(), |
||
359 |
node(), |
||
360 |
1676 |
image() |
|
361 |
{ |
||
362 |
} |
||
363 |
|||
364 |
A_DELETE_COPY(SkinHelper) |
||
365 |
|||
366 |
std::string partType; |
||
367 |
int xPos; |
||
368 |
int yPos; |
||
369 |
int width; |
||
370 |
int height; |
||
371 |
ImageRect *rect; |
||
372 |
XmlNodePtr *node; |
||
373 |
Image *image; |
||
374 |
|||
375 |
5121 |
bool loadList(const SkinParameter *const params, |
|
376 |
const size_t size) A_NONNULL(2) |
||
377 |
{ |
||
378 |
✓✓ | 103128 |
for (size_t f = 0; f < size; f ++) |
379 |
{ |
||
380 |
102928 |
const SkinParameter ¶m = params[f]; |
|
381 |
✓✓ | 102928 |
if (partType == param.name) |
382 |
{ |
||
383 |
4921 |
rect->grid[param.index] = Loader::getSubImage( |
|
384 |
image, |
||
385 |
xPos, yPos, |
||
386 |
width, height); |
||
387 |
4921 |
return true; |
|
388 |
} |
||
389 |
} |
||
390 |
return false; |
||
391 |
} |
||
392 |
}; |
||
393 |
|||
394 |
928 |
Skin *Theme::readSkin(const std::string &filename, const bool full) |
|
395 |
{ |
||
396 |
✓✓ | 928 |
if (filename.empty()) |
397 |
return nullptr; |
||
398 |
|||
399 |
922 |
const std::string path = resolveThemePath(filename); |
|
400 |
✓✗✓✓ |
1844 |
if (!VirtFs::exists(path)) |
401 |
return nullptr; |
||
402 |
XML::Document *const doc = Loader::getXml(path, |
||
403 |
UseVirtFs_true, |
||
404 |
✓✗ | 838 |
SkipError_true); |
405 |
✓✗ | 838 |
if (doc == nullptr) |
406 |
return nullptr; |
||
407 |
✓✗ | 838 |
XmlNodeConstPtr rootNode = doc->rootNode(); |
408 |
✓✗✓✗ ✗✓✗✓ |
838 |
if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "skinset")) |
409 |
{ |
||
410 |
doc->decRef(); |
||
411 |
return nullptr; |
||
412 |
} |
||
413 |
|||
414 |
✓✗✓✗ |
3352 |
const std::string skinSetImage = XML::getProperty(rootNode, "image", ""); |
415 |
|||
416 |
✗✓ | 838 |
if (skinSetImage.empty()) |
417 |
{ |
||
418 |
logger->log1("Theme::readSkin(): Skinset does not define an image!"); |
||
419 |
doc->decRef(); |
||
420 |
return nullptr; |
||
421 |
} |
||
422 |
|||
423 |
✓✗ | 838 |
Image *const dBorders = Theme::getImageFromTheme(skinSetImage); |
424 |
✓✗ | 1676 |
ImageRect *const border = new ImageRect; |
425 |
✓✗ | 1676 |
ImageRect *const images = new ImageRect; |
426 |
838 |
int padding = 3; |
|
427 |
838 |
int titlePadding = 4; |
|
428 |
838 |
int titlebarHeight = 0; |
|
429 |
838 |
int titlebarHeightRelative = 0; |
|
430 |
838 |
int closePadding = 3; |
|
431 |
838 |
int stickySpacing = 3; |
|
432 |
838 |
int stickyPadding = 3; |
|
433 |
838 |
int resizePadding = 2; |
|
434 |
✓✗ | 1676 |
StringIntMap *const mOptions = new StringIntMap; |
435 |
|||
436 |
// iterate <widget>'s |
||
437 |
✓✓ | 3352 |
for_each_xml_child_node(widgetNode, rootNode) |
438 |
{ |
||
439 |
✓✗✓✓ |
2514 |
if (!xmlNameEqual(widgetNode, "widget")) |
440 |
1676 |
continue; |
|
441 |
|||
442 |
const std::string widgetType = |
||
443 |
✓✗✓✗ |
4190 |
XML::getProperty(widgetNode, "type", "unknown"); |
444 |
✓✗ | 838 |
if (widgetType == "Window") |
445 |
{ |
||
446 |
1676 |
SkinHelper helper; |
|
447 |
✓✗ | 838 |
const int globalXPos = XML::getProperty(widgetNode, "xpos", 0); |
448 |
✓✗ | 838 |
const int globalYPos = XML::getProperty(widgetNode, "ypos", 0); |
449 |
✓✓ | 18348 |
for_each_xml_child_node(partNode, widgetNode) |
450 |
{ |
||
451 |
✓✗✓✓ |
17510 |
if (xmlNameEqual(partNode, "part")) |
452 |
{ |
||
453 |
✓✗✓✗ |
27090 |
helper.partType = XML::getProperty( |
454 |
5418 |
partNode, "type", "unknown"); |
|
455 |
✓✗ | 10836 |
helper.xPos = XML::getProperty( |
456 |
5418 |
partNode, "xpos", 0) + globalXPos; |
|
457 |
✓✗ | 10836 |
helper.yPos = XML::getProperty( |
458 |
5418 |
partNode, "ypos", 0) + globalYPos; |
|
459 |
✓✗ | 5418 |
helper.width = XML::getProperty(partNode, "width", 0); |
460 |
✓✗ | 5418 |
helper.height = XML::getProperty(partNode, "height", 0); |
461 |
✓✓✓✗ |
5418 |
if ((helper.width == 0) || (helper.height == 0)) |
462 |
continue; |
||
463 |
4921 |
helper.image = dBorders; |
|
464 |
|||
465 |
4921 |
helper.rect = border; |
|
466 |
✓✗✓✓ |
4921 |
if (!helper.loadList(skinParam, |
467 |
sizeof(skinParam) / sizeof(SkinParameter))) |
||
468 |
{ |
||
469 |
200 |
helper.rect = images; |
|
470 |
helper.loadList(imageParam, |
||
471 |
✓✗ | 200 |
sizeof(imageParam) / sizeof(SkinParameter)); |
472 |
} |
||
473 |
} |
||
474 |
✓✓✓✗ ✓✓✓✓ |
12092 |
else if (full && xmlNameEqual(partNode, "option")) |
475 |
{ |
||
476 |
const std::string name = XML::getProperty( |
||
477 |
✓✗✓✗ |
6160 |
partNode, "name", ""); |
478 |
✓✓ | 1232 |
if (name == "padding") |
479 |
{ |
||
480 |
✓✗ | 466 |
padding = XML::getProperty(partNode, "value", 3); |
481 |
} |
||
482 |
✓✓ | 766 |
else if (name == "titlePadding") |
483 |
{ |
||
484 |
✓✗ | 1 |
titlePadding = XML::getProperty(partNode, "value", 4); |
485 |
} |
||
486 |
✗✓ | 765 |
else if (name == "closePadding") |
487 |
{ |
||
488 |
closePadding = XML::getProperty(partNode, "value", 3); |
||
489 |
} |
||
490 |
✓✓ | 765 |
else if (name == "stickySpacing") |
491 |
{ |
||
492 |
✓✗ | 41 |
stickySpacing = XML::getProperty(partNode, "value", 3); |
493 |
} |
||
494 |
✗✓ | 724 |
else if (name == "stickyPadding") |
495 |
{ |
||
496 |
stickyPadding = XML::getProperty(partNode, "value", 3); |
||
497 |
} |
||
498 |
✓✓ | 724 |
else if (name == "titlebarHeight") |
499 |
{ |
||
500 |
titlebarHeight = XML::getProperty( |
||
501 |
✓✗ | 57 |
partNode, "value", 0); |
502 |
} |
||
503 |
✗✓ | 667 |
else if (name == "titlebarHeightRelative") |
504 |
{ |
||
505 |
titlebarHeightRelative = XML::getProperty( |
||
506 |
partNode, "value", 0); |
||
507 |
} |
||
508 |
✗✓ | 667 |
else if (name == "resizePadding") |
509 |
{ |
||
510 |
resizePadding = XML::getProperty( |
||
511 |
partNode, "value", 2); |
||
512 |
} |
||
513 |
else |
||
514 |
{ |
||
515 |
✓✗✓✗ |
667 |
(*mOptions)[name] = XML::getProperty( |
516 |
partNode, "value", 0); |
||
517 |
} |
||
518 |
} |
||
519 |
} |
||
520 |
} |
||
521 |
else |
||
522 |
{ |
||
523 |
logger->log("Theme::readSkin(): Unknown widget type '%s'", |
||
524 |
widgetType.c_str()); |
||
525 |
} |
||
526 |
} |
||
527 |
|||
528 |
✓✗ | 838 |
if (dBorders != nullptr) |
529 |
✓✗ | 838 |
dBorders->decRef(); |
530 |
|||
531 |
✓✗✓✗ |
3352 |
(*mOptions)["closePadding"] = closePadding; |
532 |
✓✗✓✗ |
3352 |
(*mOptions)["stickyPadding"] = stickyPadding; |
533 |
✓✗✓✗ |
3352 |
(*mOptions)["stickySpacing"] = stickySpacing; |
534 |
✓✗✓✗ |
3352 |
(*mOptions)["titlebarHeight"] = titlebarHeight; |
535 |
✓✗✓✗ |
3352 |
(*mOptions)["titlebarHeightRelative"] = titlebarHeightRelative; |
536 |
✓✗✓✗ |
3352 |
(*mOptions)["resizePadding"] = resizePadding; |
537 |
|||
538 |
Skin *const skin = new Skin(border, images, filename, "", padding, |
||
539 |
✓✗✓✗ ✓✗ |
3352 |
titlePadding, mOptions); |
540 |
838 |
delete images; |
|
541 |
✓✗ | 838 |
skin->updateAlpha(mMinimumOpacity); |
542 |
✓✗ | 838 |
doc->decRef(); |
543 |
return skin; |
||
544 |
} |
||
545 |
|||
546 |
227 |
bool Theme::tryThemePath(const std::string &themeName) |
|
547 |
{ |
||
548 |
✓✗ | 227 |
if (!themeName.empty()) |
549 |
{ |
||
550 |
227 |
const std::string path = defaultThemePath + themeName; |
|
551 |
✓✗✓✗ |
454 |
if (VirtFs::exists(path)) |
552 |
{ |
||
553 |
227 |
mThemePath = path; |
|
554 |
227 |
mThemeName = themeName; |
|
555 |
✓✗ | 227 |
if (theme != nullptr) |
556 |
✓✗✓✗ |
908 |
theme->loadColors(""); |
557 |
454 |
return true; |
|
558 |
} |
||
559 |
} |
||
560 |
|||
561 |
return false; |
||
562 |
} |
||
563 |
|||
564 |
2 |
void Theme::fillSkinsList(StringVect &list) |
|
565 |
{ |
||
566 |
✓✗✓✗ |
10 |
VirtFs::getDirs(branding.getStringValue("guiThemePath"), list); |
567 |
2 |
std::sort(list.begin(), list.end()); |
|
568 |
2 |
} |
|
569 |
|||
570 |
2 |
void Theme::fillFontsList(StringVect &list) |
|
571 |
{ |
||
572 |
2 |
VirtFs::permitLinks(true); |
|
573 |
✓✗✓✗ |
10 |
VirtFs::getFiles(branding.getStringValue("fontsPath"), list); |
574 |
4 |
std::sort(list.begin(), list.end()); |
|
575 |
2 |
VirtFs::permitLinks(false); |
|
576 |
2 |
} |
|
577 |
|||
578 |
2 |
void Theme::fillSoundsList(StringVect &list) |
|
579 |
{ |
||
580 |
VirtFs::List *const skins = VirtFs::enumerateFiles( |
||
581 |
✓✗✓✗ |
10 |
branding.getStringValue("systemsounds")); |
582 |
|||
583 |
✓✓ | 58 |
FOR_EACH (StringVectCIter, i, skins->names) |
584 |
{ |
||
585 |
✓✗✓✗ ✓✗ |
276 |
if (!VirtFs::isDirectory((branding.getStringValue( |
586 |
✓✗ | 138 |
"systemsounds") + *i))) |
587 |
{ |
||
588 |
138 |
std::string str = *i; |
|
589 |
✓✗✓✗ ✓✓ |
184 |
if (findCutLast(str, ".ogg")) |
590 |
✓✗ | 38 |
list.push_back(str); |
591 |
} |
||
592 |
} |
||
593 |
|||
594 |
2 |
VirtFs::freeList(skins); |
|
595 |
4 |
std::sort(list.begin(), list.end()); |
|
596 |
2 |
} |
|
597 |
|||
598 |
227 |
void Theme::selectSkin() |
|
599 |
{ |
||
600 |
227 |
prepareThemePath(); |
|
601 |
454 |
mScreenDensity = graphicsManager.getDensityString(); |
|
602 |
227 |
} |
|
603 |
|||
604 |
227 |
void Theme::prepareThemePath() |
|
605 |
{ |
||
606 |
227 |
initDefaultThemePath(); |
|
607 |
|||
608 |
227 |
mThemePath.clear(); |
|
609 |
227 |
mThemeName.clear(); |
|
610 |
|||
611 |
// Try theme from settings |
||
612 |
✓✗✓✗ ✗✓ |
1135 |
if (tryThemePath(config.getStringValue("theme"))) |
613 |
return; |
||
614 |
|||
615 |
// Try theme from branding |
||
616 |
if (tryThemePath(branding.getStringValue("theme"))) |
||
617 |
return; |
||
618 |
|||
619 |
if (mThemePath.empty()) |
||
620 |
mThemePath = "graphics/gui"; |
||
621 |
|||
622 |
theme->loadColors(mThemePath); |
||
623 |
|||
624 |
logger->log("Selected Theme: " + mThemePath); |
||
625 |
} |
||
626 |
|||
627 |
3436 |
std::string Theme::resolveThemePath(const std::string &path) |
|
628 |
{ |
||
629 |
// Need to strip off any dye info for the existence tests |
||
630 |
3436 |
const int pos = CAST_S32(path.find('|')); |
|
631 |
6872 |
std::string file; |
|
632 |
✗✓ | 3436 |
if (pos > 0) |
633 |
file = path.substr(0, pos); |
||
634 |
else |
||
635 |
file = path; |
||
636 |
|||
637 |
// File with path |
||
638 |
✗✓ | 3436 |
if (file.find('/') != std::string::npos) |
639 |
{ |
||
640 |
// Might be a valid path already |
||
641 |
if (VirtFs::exists(file)) |
||
642 |
return path; |
||
643 |
} |
||
644 |
|||
645 |
// Try the theme |
||
646 |
✓✗ | 10308 |
file = pathJoin(getThemePath(), file); |
647 |
|||
648 |
✓✗✓✓ |
6872 |
if (VirtFs::exists(file)) |
649 |
✓✗ | 3930 |
return pathJoin(getThemePath(), path); |
650 |
|||
651 |
// Backup |
||
652 |
✓✗✓✗ ✓✗ |
7355 |
return pathJoin(branding.getStringValue("guiPath"), path); |
653 |
} |
||
654 |
|||
655 |
844 |
Image *Theme::getImageFromTheme(const std::string &path) |
|
656 |
{ |
||
657 |
✓✗ | 1688 |
return Loader::getImage(resolveThemePath(path)); |
658 |
} |
||
659 |
|||
660 |
153 |
ImageSet *Theme::getImageSetFromTheme(const std::string &path, |
|
661 |
const int w, const int h) |
||
662 |
{ |
||
663 |
✓✗ | 306 |
return Loader::getImageSet(resolveThemePath(path), w, h); |
664 |
} |
||
665 |
|||
666 |
#define themeEnumStart(name) #name, |
||
667 |
#define themeEnum(name) #name, |
||
668 |
#define themeEnumEnd(name) |
||
669 |
|||
670 |
172066 |
static int readColorType(const std::string &type) |
|
671 |
{ |
||
672 |
static const std::string colors[CAST_SIZE( |
||
673 |
ThemeColorId::THEME_COLORS_END)] = |
||
674 |
{ |
||
675 |
#include "gui/themecolortype.inc" |
||
676 |
✓✓✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✗✓✓ |
172524 |
}; |
677 |
|||
678 |
✓✗ | 172066 |
if (type.empty()) |
679 |
return -1; |
||
680 |
|||
681 |
✓✓ | 42644220 |
for (int i = 0; i < CAST_S32(ThemeColorId::THEME_COLORS_END); i++) |
682 |
{ |
||
683 |
✓✓ | 21399063 |
if (compareStrI(type, colors[i]) == 0) |
684 |
return i; |
||
685 |
} |
||
686 |
|||
687 |
return -1; |
||
688 |
} |
||
689 |
|||
690 |
THEMECOLORTYPE_VOID |
||
691 |
|||
692 |
#undef themeEnumStart |
||
693 |
#undef themeEnum |
||
694 |
#undef themeEnumEnd |
||
695 |
#undef THEMECOLORTYPE_VOID |
||
696 |
|||
697 |
101242 |
static Color readColor(const std::string &description) |
|
698 |
{ |
||
699 |
101242 |
const int size = static_cast<int>(description.length()); |
|
700 |
✓✗✗✓ ✓✗ |
202484 |
if (size < 7 || description[0] != '#') |
701 |
{ |
||
702 |
logger->log("Error, invalid theme color palette: %s", |
||
703 |
description.c_str()); |
||
704 |
return Palette::BLACK; |
||
705 |
} |
||
706 |
|||
707 |
unsigned int v = 0; |
||
708 |
✓✓ | 1316146 |
for (int i = 1; i < 7; ++i) |
709 |
{ |
||
710 |
1214904 |
signed const char c = description[i]; |
|
711 |
int n; |
||
712 |
|||
713 |
✓✓ | 607452 |
if ('0' <= c && c <= '9') |
714 |
{ |
||
715 |
356390 |
n = c - '0'; |
|
716 |
} |
||
717 |
✓✓ | 251062 |
else if ('A' <= c && c <= 'F') |
718 |
{ |
||
719 |
2724 |
n = c - 'A' + 10; |
|
720 |
} |
||
721 |
✓✗ | 248338 |
else if ('a' <= c && c <= 'f') |
722 |
{ |
||
723 |
248338 |
n = c - 'a' + 10; |
|
724 |
} |
||
725 |
else |
||
726 |
{ |
||
727 |
logger->log("Error, invalid theme color palette: %s", |
||
728 |
description.c_str()); |
||
729 |
return Palette::BLACK; |
||
730 |
} |
||
731 |
|||
732 |
607452 |
v = (v << 4) | n; |
|
733 |
} |
||
734 |
|||
735 |
101242 |
return Color(v); |
|
736 |
} |
||
737 |
|||
738 |
101242 |
static GradientTypeT readColorGradient(const std::string &grad) |
|
739 |
{ |
||
740 |
static const std::string grads[] = |
||
741 |
{ |
||
742 |
"STATIC", |
||
743 |
"PULSE", |
||
744 |
"SPECTRUM", |
||
745 |
"RAINBOW" |
||
746 |
✓✓✓✗ ✓✗✓✗ ✓✗✓✗ ✗✗✓✓ |
101252 |
}; |
747 |
|||
748 |
✓✓ | 101242 |
if (grad.empty()) |
749 |
return GradientType::STATIC; |
||
750 |
|||
751 |
✓✗ | 908 |
for (int i = 0; i < 4; i++) |
752 |
{ |
||
753 |
✗✓ | 908 |
if (compareStrI(grad, grads[i]) != 0) |
754 |
return static_cast<GradientTypeT>(i); |
||
755 |
} |
||
756 |
|||
757 |
return GradientType::STATIC; |
||
758 |
} |
||
759 |
|||
760 |
2724 |
static int readProgressType(const std::string &type) |
|
761 |
{ |
||
762 |
static const std::string colors[CAST_SIZE( |
||
763 |
ProgressColorId::THEME_PROG_END)] = |
||
764 |
{ |
||
765 |
"HP", |
||
766 |
"HP_POISON", |
||
767 |
"MP", |
||
768 |
"NO_MP", |
||
769 |
"EXP", |
||
770 |
"INVY_SLOTS", |
||
771 |
"WEIGHT", |
||
772 |
"JOB", |
||
773 |
"UPDATE", |
||
774 |
"MONEY", |
||
775 |
"ARROWS", |
||
776 |
"STATUS" |
||
777 |
✓✓✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✓✗✓✗ ✗✗✓✓ |
2750 |
}; |
778 |
|||
779 |
✓✗ | 2724 |
if (type.empty()) |
780 |
return -1; |
||
781 |
|||
782 |
✓✗ | 32688 |
for (int i = 0; i < CAST_S32(ProgressColorId::THEME_PROG_END); i++) |
783 |
{ |
||
784 |
✓✓ | 17706 |
if (compareStrI(type, colors[i]) == 0) |
785 |
return i; |
||
786 |
} |
||
787 |
|||
788 |
return -1; |
||
789 |
} |
||
790 |
|||
791 |
227 |
void Theme::loadColors(std::string file) |
|
792 |
{ |
||
793 |
✓✗ | 227 |
if (file.empty()) |
794 |
file = "colors.xml"; |
||
795 |
else |
||
796 |
file = pathJoin(file, "colors.xml"); |
||
797 |
|||
798 |
454 |
XML::Document *const doc = Loader::getXml(resolveThemePath(file), |
|
799 |
UseVirtFs_true, |
||
800 |
✓✗ | 227 |
SkipError_false); |
801 |
✓✗ | 227 |
if (doc == nullptr) |
802 |
return; |
||
803 |
227 |
XmlNodeConstPtrConst root = doc->rootNode(); |
|
804 |
|||
805 |
✓✗✗✓ ✗✓ |
227 |
if ((root == nullptr) || !xmlNameEqual(root, "colors")) |
806 |
{ |
||
807 |
logger->log("Error loading colors file: %s", file.c_str()); |
||
808 |
doc->decRef(); |
||
809 |
return; |
||
810 |
} |
||
811 |
|||
812 |
227 |
logger->log("Loading colors file: %s", file.c_str()); |
|
813 |
|||
814 |
✓✓ | 7264 |
for_each_xml_child_node(paletteNode, root) |
815 |
{ |
||
816 |
✓✓ | 7037 |
if (xmlNameEqual(paletteNode, "progressbar")) |
817 |
{ |
||
818 |
✓✗ | 13620 |
const int type = readProgressType(XML::getProperty( |
819 |
✓✗ | 2724 |
paletteNode, "id", "")); |
820 |
✓✗ | 2724 |
if (type < 0) |
821 |
continue; |
||
822 |
|||
823 |
✓✗ | 19068 |
mProgressColors[type] = new DyePalette(XML::getProperty( |
824 |
✓✗✓✗ |
2724 |
paletteNode, "color", ""), 6); |
825 |
} |
||
826 |
✓✓ | 4313 |
else if (!xmlNameEqual(paletteNode, "palette")) |
827 |
{ |
||
828 |
continue; |
||
829 |
} |
||
830 |
|||
831 |
3405 |
const int paletteId = XML::getProperty(paletteNode, "id", 1); |
|
832 |
✓✗ | 3405 |
if (paletteId < 0 || paletteId >= THEME_PALETTES) |
833 |
continue; |
||
834 |
|||
835 |
✓✓ | 206570 |
for_each_xml_child_node(node, paletteNode) |
836 |
{ |
||
837 |
✓✓ | 203165 |
if (xmlNameEqual(node, "color")) |
838 |
{ |
||
839 |
✓✗ | 497130 |
const std::string id = XML::getProperty(node, "id", ""); |
840 |
✓✗ | 101242 |
const int type = readColorType(id); |
841 |
✓✗ | 101242 |
if (type < 0) |
842 |
9080 |
continue; |
|
843 |
|||
844 |
✓✗✓✗ |
497130 |
const std::string temp = XML::getProperty(node, "color", ""); |
845 |
✓✗ | 101242 |
if (temp.empty()) |
846 |
continue; |
||
847 |
|||
848 |
✓✗ | 101242 |
const Color color = readColor(temp); |
849 |
const GradientTypeT grad = readColorGradient( |
||
850 |
✓✗✓✗ ✓✗ |
506210 |
XML::getProperty(node, "effect", "")); |
851 |
101242 |
mColors[paletteId * CAST_SIZE( |
|
852 |
202484 |
ThemeColorId::THEME_COLORS_END) + type].set( |
|
853 |
101242 |
type, color, grad, 10); |
|
854 |
|||
855 |
✓✗✓✗ ✓✓ |
404968 |
if (!findLast(id, "_OUTLINE")) |
856 |
{ |
||
857 |
✓✗✓✗ |
141648 |
const int type2 = readColorType(id + "_OUTLINE"); |
858 |
✓✓ | 70824 |
if (type2 < 0) |
859 |
continue; |
||
860 |
const int idx = paletteId |
||
861 |
61744 |
* CAST_S32(ThemeColorId::THEME_COLORS_END); |
|
862 |
✓✗ | 185232 |
mColors[idx + type2] = mColors[idx + type]; |
863 |
} |
||
864 |
} |
||
865 |
} |
||
866 |
} |
||
867 |
227 |
doc->decRef(); |
|
868 |
} |
||
869 |
|||
870 |
#define loadGrid() \ |
||
871 |
{ \ |
||
872 |
const ImageRect &rect = skin->getBorder(); \ |
||
873 |
for (int f = start; f <= end; f ++) \ |
||
874 |
{ \ |
||
875 |
if (rect.grid[f]) \ |
||
876 |
{ \ |
||
877 |
image.grid[f] = rect.grid[f]; \ |
||
878 |
image.grid[f]->incRef(); \ |
||
879 |
} \ |
||
880 |
} \ |
||
881 |
} |
||
882 |
|||
883 |
210 |
void Theme::loadRect(ImageRect &image, |
|
884 |
const std::string &name, |
||
885 |
const std::string &name2, |
||
886 |
const int start, |
||
887 |
const int end) |
||
888 |
{ |
||
889 |
Skin *const skin = load(name, |
||
890 |
name2, |
||
891 |
false, |
||
892 |
✓✗ | 420 |
Theme::getThemePath()); |
893 |
✓✗ | 210 |
if (skin != nullptr) |
894 |
{ |
||
895 |
✓✓✓✓ |
210 |
loadGrid() |
896 |
210 |
unload(skin); |
|
897 |
} |
||
898 |
210 |
} |
|
899 |
|||
900 |
43 |
Skin *Theme::loadSkinRect(ImageRect &image, |
|
901 |
const std::string &name, |
||
902 |
const std::string &name2, |
||
903 |
const int start, |
||
904 |
const int end) |
||
905 |
{ |
||
906 |
Skin *const skin = load(name, |
||
907 |
name2, |
||
908 |
true, |
||
909 |
✓✗ | 86 |
Theme::getThemePath()); |
910 |
✓✗ | 43 |
if (skin != nullptr) |
911 |
✓✓✓✗ |
43 |
loadGrid() |
912 |
43 |
return skin; |
|
913 |
} |
||
914 |
|||
915 |
262 |
void Theme::unloadRect(const ImageRect &rect, |
|
916 |
const int start, |
||
917 |
const int end) |
||
918 |
{ |
||
919 |
✓✓ | 2620 |
for (int f = start; f <= end; f ++) |
920 |
{ |
||
921 |
✓✓ | 2358 |
if (rect.grid[f] != nullptr) |
922 |
1286 |
rect.grid[f]->decRef(); |
|
923 |
} |
||
924 |
262 |
} |
|
925 |
|||
926 |
59 |
Image *Theme::getImageFromThemeXml(const std::string &name, |
|
927 |
const std::string &name2) |
||
928 |
{ |
||
929 |
✓✗ | 59 |
if (theme == nullptr) |
930 |
return nullptr; |
||
931 |
|||
932 |
59 |
Skin *const skin = theme->load(name, |
|
933 |
name2, |
||
934 |
false, |
||
935 |
✓✗ | 118 |
Theme::getThemePath()); |
936 |
✓✗ | 59 |
if (skin != nullptr) |
937 |
{ |
||
938 |
59 |
const ImageRect &rect = skin->getBorder(); |
|
939 |
✓✓ | 59 |
if (rect.grid[0] != nullptr) |
940 |
{ |
||
941 |
53 |
Image *const image = rect.grid[0]; |
|
942 |
53 |
image->incRef(); |
|
943 |
53 |
theme->unload(skin); |
|
944 |
53 |
return image; |
|
945 |
} |
||
946 |
6 |
theme->unload(skin); |
|
947 |
} |
||
948 |
return nullptr; |
||
949 |
} |
||
950 |
|||
951 |
1 |
ImageSet *Theme::getImageSetFromThemeXml(const std::string &name, |
|
952 |
const std::string &name2, |
||
953 |
const int w, const int h) |
||
954 |
{ |
||
955 |
✓✗ | 1 |
if (theme == nullptr) |
956 |
return nullptr; |
||
957 |
|||
958 |
1 |
Skin *const skin = theme->load(name, |
|
959 |
name2, |
||
960 |
false, |
||
961 |
✓✗ | 2 |
Theme::getThemePath()); |
962 |
✓✗ | 1 |
if (skin != nullptr) |
963 |
{ |
||
964 |
1 |
const ImageRect &rect = skin->getBorder(); |
|
965 |
✗✓ | 1 |
if (rect.grid[0] != nullptr) |
966 |
{ |
||
967 |
Image *const image = rect.grid[0]; |
||
968 |
const SDL_Rect &rect2 = image->mBounds; |
||
969 |
if ((rect2.w != 0U) && (rect2.h != 0U)) |
||
970 |
{ |
||
971 |
ImageSet *const imageSet = Loader::getSubImageSet( |
||
972 |
image, w, h); |
||
973 |
theme->unload(skin); |
||
974 |
return imageSet; |
||
975 |
} |
||
976 |
} |
||
977 |
1 |
theme->unload(skin); |
|
978 |
} |
||
979 |
return nullptr; |
||
980 |
} |
||
981 |
|||
982 |
#define readValue(name) \ |
||
983 |
{ \ |
||
984 |
tmpData = reinterpret_cast<XmlChar*>( \ |
||
985 |
XmlNodeGetContent(infoNode)); \ |
||
986 |
info->name = tmpData; \ |
||
987 |
XmlFree(tmpData); \ |
||
988 |
} |
||
989 |
|||
990 |
#define readIntValue(name) \ |
||
991 |
{ \ |
||
992 |
tmpData = reinterpret_cast<XmlChar*>( \ |
||
993 |
XmlNodeGetContent(infoNode)); \ |
||
994 |
info->name = atoi(tmpData); \ |
||
995 |
XmlFree(tmpData); \ |
||
996 |
} |
||
997 |
|||
998 |
#define readFloatValue(name) \ |
||
999 |
{ \ |
||
1000 |
tmpData = reinterpret_cast<XmlChar*>( \ |
||
1001 |
XmlNodeGetContent(infoNode)); \ |
||
1002 |
info->name = static_cast<float>(atof(tmpData)); \ |
||
1003 |
XmlFree(tmpData); \ |
||
1004 |
} |
||
1005 |
|||
1006 |
4 |
ThemeInfo *Theme::loadInfo(const std::string &themeName) |
|
1007 |
{ |
||
1008 |
8 |
std::string path; |
|
1009 |
✗✓ | 4 |
if (themeName.empty()) |
1010 |
{ |
||
1011 |
path = "graphics/gui/info.xml"; |
||
1012 |
} |
||
1013 |
else |
||
1014 |
{ |
||
1015 |
✓✗✓✗ |
28 |
path = pathJoin(defaultThemePath, |
1016 |
themeName, |
||
1017 |
4 |
"info.xml"); |
|
1018 |
} |
||
1019 |
✓✗✓✗ |
8 |
logger->log("loading: " + path); |
1020 |
XML::Document *const doc = Loader::getXml(path, |
||
1021 |
UseVirtFs_true, |
||
1022 |
✓✗ | 4 |
SkipError_false); |
1023 |
✓✗ | 4 |
if (doc == nullptr) |
1024 |
return nullptr; |
||
1025 |
✓✗ | 4 |
XmlNodeConstPtrConst rootNode = doc->rootNode(); |
1026 |
|||
1027 |
✓✗✓✗ ✗✓✗✓ |
4 |
if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "info")) |
1028 |
{ |
||
1029 |
doc->decRef(); |
||
1030 |
return nullptr; |
||
1031 |
} |
||
1032 |
|||
1033 |
✓✗ | 4 |
ThemeInfo *const info = new ThemeInfo; |
1034 |
|||
1035 |
✓✗ | 4 |
const std::string fontSize2("fontSize_" + mScreenDensity); |
1036 |
✓✗ | 8 |
const std::string npcfontSize2("npcfontSize_" + mScreenDensity); |
1037 |
4 |
XmlChar *tmpData = nullptr; |
|
1038 |
✓✓ | 32 |
for_each_xml_child_node(infoNode, rootNode) |
1039 |
{ |
||
1040 |
✓✗✓✓ |
28 |
if (xmlNameEqual(infoNode, "name")) |
1041 |
✓✗✓✗ |
8 |
readValue(name) |
1042 |
✓✗✓✓ |
24 |
else if (xmlNameEqual(infoNode, "copyright")) |
1043 |
✓✗✓✗ |
8 |
readValue(copyright) |
1044 |
✓✗✗✓ |
20 |
else if (xmlNameEqual(infoNode, "font")) |
1045 |
readValue(font) |
||
1046 |
✓✗✗✓ |
20 |
else if (xmlNameEqual(infoNode, "boldFont")) |
1047 |
readValue(boldFont) |
||
1048 |
✓✗✗✓ |
20 |
else if (xmlNameEqual(infoNode, "particleFont")) |
1049 |
readValue(particleFont) |
||
1050 |
✓✗✗✓ |
20 |
else if (xmlNameEqual(infoNode, "helpFont")) |
1051 |
readValue(helpFont) |
||
1052 |
✓✗✗✓ |
20 |
else if (xmlNameEqual(infoNode, "secureFont")) |
1053 |
readValue(secureFont) |
||
1054 |
✓✗✗✓ |
20 |
else if (xmlNameEqual(infoNode, "npcFont")) |
1055 |
readValue(npcFont) |
||
1056 |
✓✗✗✓ |
20 |
else if (xmlNameEqual(infoNode, "japanFont")) |
1057 |
readValue(japanFont) |
||
1058 |
✓✗✗✓ |
20 |
else if (xmlNameEqual(infoNode, "chinaFont")) |
1059 |
readValue(chinaFont) |
||
1060 |
✓✗✗✓ |
20 |
else if (xmlNameEqual(infoNode, "fontSize")) |
1061 |
readIntValue(fontSize) |
||
1062 |
✓✗✗✓ |
20 |
else if (xmlNameEqual(infoNode, "npcfontSize")) |
1063 |
readIntValue(npcfontSize) |
||
1064 |
✓✗✓✓ |
20 |
else if (xmlNameEqual(infoNode, "guialpha")) |
1065 |
✓✗✓✗ |
8 |
readFloatValue(guiAlpha) |
1066 |
✓✗✗✓ |
16 |
else if (xmlNameEqual(infoNode, fontSize2.c_str())) |
1067 |
readIntValue(fontSize) |
||
1068 |
✓✗✗✓ |
16 |
else if (xmlNameEqual(infoNode, npcfontSize2.c_str())) |
1069 |
readIntValue(npcfontSize) |
||
1070 |
} |
||
1071 |
✓✗ | 4 |
doc->decRef(); |
1072 |
4 |
return info; |
|
1073 |
} |
||
1074 |
|||
1075 |
4 |
ThemeColorIdT Theme::getIdByChar(const signed char c, bool &valid) const |
|
1076 |
{ |
||
1077 |
8 |
const CharColors::const_iterator it = mCharColors.find(c); |
|
1078 |
✓✓ | 8 |
if (it != mCharColors.end()) |
1079 |
{ |
||
1080 |
2 |
valid = true; |
|
1081 |
2 |
return static_cast<ThemeColorIdT>((*it).second); |
|
1082 |
} |
||
1083 |
|||
1084 |
2 |
valid = false; |
|
1085 |
2 |
return ThemeColorId::BROWSERBOX; |
|
1086 |
✓✗✓✗ |
3 |
} |
Generated by: GCOVR (Version 3.3) |