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