diff options
Diffstat (limited to 'src/gui/theme.cpp')
-rw-r--r-- | src/gui/theme.cpp | 1283 |
1 files changed, 0 insertions, 1283 deletions
diff --git a/src/gui/theme.cpp b/src/gui/theme.cpp deleted file mode 100644 index cbc0d654c..000000000 --- a/src/gui/theme.cpp +++ /dev/null @@ -1,1283 +0,0 @@ -/* - * The ManaPlus Client - * Copyright (C) 2008 The Legend of Mazzeroth Development Team - * Copyright (C) 2009 Aethyra Development Team - * Copyright (C) 2009 The Mana World Development Team - * Copyright (C) 2009-2010 The Mana Developers - * Copyright (C) 2011-2017 The ManaPlus Developers - * - * This file is part of The ManaPlus Client. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "gui/theme.h" - -#include "configuration.h" -#include "graphicsmanager.h" - -#include "const/gui/theme.h" - -#include "fs/virtfs/fs.h" -#include "fs/virtfs/list.h" - -#include "gui/skin.h" -#include "gui/themeinfo.h" - -#include "resources/imagerect.h" - -#include "resources/dye/dyepalette.h" - -#include "resources/image/image.h" - -#include "resources/loaders/imageloader.h" -#include "resources/loaders/imagesetloader.h" -#include "resources/loaders/subimageloader.h" -#include "resources/loaders/subimagesetloader.h" -#include "resources/loaders/xmlloader.h" - -#include "utils/dtor.h" -#include "utils/foreach.h" - -#include "debug.h" - -static std::string defaultThemePath; - -std::string Theme::mThemePath; -std::string Theme::mThemeName; -std::string Theme::mScreenDensity; - -Theme *theme = nullptr; - -// Set the theme path... -static void initDefaultThemePath() -{ - defaultThemePath = branding.getStringValue("guiThemePath"); - - logger->log("defaultThemePath: " + defaultThemePath); - if (!defaultThemePath.empty() && - VirtFs::isDirectory(defaultThemePath)) - { - return; - } - defaultThemePath = "themes/"; -} - -Theme::Theme() : - Palette(CAST_S32(ThemeColorId::THEME_COLORS_END) * THEME_PALETTES), - mSkins(), - mMinimumOpacity(-1.0F), - mProgressColors(ProgressColors(CAST_SIZE( - ProgressColorId::THEME_PROG_END))) -{ - initDefaultThemePath(); - - config.addListener("guialpha", this); - - mColors[CAST_SIZE(ThemeColorId::HIGHLIGHT)].ch = 'H'; - mColors[CAST_SIZE(ThemeColorId::CHAT)].ch = 'C'; - mColors[CAST_SIZE(ThemeColorId::GM)].ch = 'G'; - mColors[CAST_SIZE(ThemeColorId::GLOBAL)].ch = 'g'; - mColors[CAST_SIZE(ThemeColorId::PLAYER)].ch = 'Y'; - mColors[CAST_SIZE(ThemeColorId::WHISPER_TAB)].ch = 'W'; - mColors[CAST_SIZE(ThemeColorId::WHISPER_TAB_OFFLINE)].ch = 'w'; - mColors[CAST_SIZE(ThemeColorId::IS)].ch = 'I'; - mColors[CAST_SIZE(ThemeColorId::PARTY_CHAT_TAB)].ch = 'P'; - mColors[CAST_SIZE(ThemeColorId::GUILD_CHAT_TAB)].ch = 'U'; - mColors[CAST_SIZE(ThemeColorId::SERVER)].ch = 'S'; - mColors[CAST_SIZE(ThemeColorId::LOGGER)].ch = 'L'; - mColors[CAST_SIZE(ThemeColorId::HYPERLINK)].ch = '<'; - mColors[CAST_SIZE(ThemeColorId::SELFNICK)].ch = 's'; - mColors[CAST_SIZE(ThemeColorId::OLDCHAT)].ch = 'o'; - mColors[CAST_SIZE(ThemeColorId::AWAYCHAT)].ch = 'a'; - mCharColors['H'] = CAST_S32(ThemeColorId::HIGHLIGHT); - mCharColors['C'] = CAST_S32(ThemeColorId::CHAT); - mCharColors['G'] = CAST_S32(ThemeColorId::GM); - mCharColors['g'] = CAST_S32(ThemeColorId::GLOBAL); - mCharColors['Y'] = CAST_S32(ThemeColorId::PLAYER); - mCharColors['W'] = CAST_S32(ThemeColorId::WHISPER_TAB); - mCharColors['w'] = CAST_S32(ThemeColorId::WHISPER_TAB_OFFLINE); - mCharColors['I'] = CAST_S32(ThemeColorId::IS); - mCharColors['P'] = CAST_S32(ThemeColorId::PARTY_CHAT_TAB); - mCharColors['U'] = CAST_S32(ThemeColorId::GUILD_CHAT_TAB); - mCharColors['S'] = CAST_S32(ThemeColorId::SERVER); - mCharColors['L'] = CAST_S32(ThemeColorId::LOGGER); - mCharColors['<'] = CAST_S32(ThemeColorId::HYPERLINK); - mCharColors['s'] = CAST_S32(ThemeColorId::SELFNICK); - mCharColors['o'] = CAST_S32(ThemeColorId::OLDCHAT); - mCharColors['a'] = CAST_S32(ThemeColorId::AWAYCHAT); - - // here need use outlined colors - mCharColors['H' | 0x80] - = CAST_S32(ThemeColorId::HIGHLIGHT_OUTLINE); - mCharColors['C' | 0x80] = CAST_S32(ThemeColorId::CHAT_OUTLINE); - mCharColors['G' | 0x80] = CAST_S32(ThemeColorId::GM_OUTLINE); - mCharColors['g' | 0x80] = CAST_S32(ThemeColorId::GLOBAL_OUTLINE); - mCharColors['Y' | 0x80] = CAST_S32(ThemeColorId::PLAYER_OUTLINE); - mCharColors['W' | 0x80] - = CAST_S32(ThemeColorId::WHISPER_TAB_OUTLINE); - mCharColors['w' | 0x80] - = CAST_S32(ThemeColorId::WHISPER_TAB_OFFLINE_OUTLINE); - mCharColors['I' | 0x80] = CAST_S32(ThemeColorId::IS_OUTLINE); - mCharColors['P' | 0x80] - = CAST_S32(ThemeColorId::PARTY_CHAT_TAB_OUTLINE); - mCharColors['U' | 0x80] - = CAST_S32(ThemeColorId::GUILD_CHAT_TAB_OUTLINE); - mCharColors['S' | 0x80] = CAST_S32(ThemeColorId::SERVER_OUTLINE); - mCharColors['L' | 0x80] = CAST_S32(ThemeColorId::LOGGER_OUTLINE); - mCharColors['<' | 0x80] - = CAST_S32(ThemeColorId::HYPERLINK_OUTLINE); - mCharColors['s' | 0x80] = CAST_S32(ThemeColorId::SELFNICK_OUTLINE); - mCharColors['o' | 0x80] = CAST_S32(ThemeColorId::OLDCHAT_OUTLINE); - mCharColors['a' | 0x80] = CAST_S32(ThemeColorId::AWAYCHAT_OUTLINE); -} - -Theme::~Theme() -{ - delete_all(mSkins); - config.removeListener("guialpha", this); - CHECKLISTENERS - delete_all(mProgressColors); -} - -Color Theme::getProgressColor(const ProgressColorIdT type, - const float progress) -{ - int color[3] = {0, 0, 0}; - - if (theme != nullptr) - { - const DyePalette *const dye - = theme->mProgressColors[CAST_SIZE(type)]; - - if (dye != nullptr) - { - dye->getColor(progress, color); - } - else - { - logger->log("color not found: " - + toString(CAST_S32(type))); - } - } - - return Color(color[0], color[1], color[2]); -} - -Skin *Theme::load(const std::string &filename, - const std::string &filename2, - const bool full, - const std::string &restrict defaultPath) -{ - // Check if this skin was already loaded - - const SkinIterator skinIterator = mSkins.find(filename); - if (mSkins.end() != skinIterator) - { - if (skinIterator->second != nullptr) - skinIterator->second->instances++; - return skinIterator->second; - } - - Skin *skin = nullptr; - if (mScreenDensity.empty()) - { // if no density detected - skin = readSkin(filename, full); - if ((skin == nullptr) && !filename2.empty() && filename2 != filename) - skin = readSkin(filename2, full); - if ((skin == nullptr) && filename2 != "window.xml") - skin = readSkin("window.xml", full); - } - else - { // first use correct density images - const std::string endStr("_" + mScreenDensity + ".xml"); - std::string name = filename; - if (findCutLast(name, ".xml")) - skin = readSkin(name + endStr, full); - if (skin == nullptr) - skin = readSkin(filename, full); - if ((skin == nullptr) && !filename2.empty() && filename2 != filename) - { - name = filename2; - if (findCutLast(name, ".xml")) - skin = readSkin(name + endStr, full); - if (skin == nullptr) - skin = readSkin(filename2, full); - } - if ((skin == nullptr) && filename2 != "window.xml") - { - skin = readSkin("window" + endStr, full); - if (skin == nullptr) - skin = readSkin("window.xml", full); - } - } - - if (skin == nullptr) - { - // Try falling back on the defaultPath if this makes sense - if (filename != defaultPath) - { - logger->log("Error loading skin '%s', falling back on default.", - filename.c_str()); - - skin = readSkin(defaultPath, full); - } - - if (skin == nullptr) - { - logger->log(strprintf("Error: Loading default skin '%s' failed. " - "Make sure the skin file is valid.", - defaultPath.c_str())); - } - } - - mSkins[filename] = skin; - return skin; -} - -void Theme::unload(Skin *const skin) -{ - if (skin == nullptr) - return; - skin->instances --; - if (skin->instances == 0) - { - SkinIterator it = mSkins.begin(); - const SkinIterator it_end = mSkins.end(); - while (it != it_end) - { - if (it->second == skin) - { - mSkins.erase(it); - break; - } - ++ it; - } - delete skin; - } -} - -void Theme::setMinimumOpacity(const float minimumOpacity) -{ - if (minimumOpacity > 1.0F) - return; - - mMinimumOpacity = minimumOpacity; - updateAlpha(); -} - -void Theme::updateAlpha() -{ - FOR_EACH (SkinIterator, iter, mSkins) - { - Skin *const skin = iter->second; - if (skin != nullptr) - skin->updateAlpha(mMinimumOpacity); - } -} - -void Theme::optionChanged(const std::string &name A_UNUSED) -{ - updateAlpha(); -} - -struct SkinParameter final -{ - A_DEFAULT_COPY(SkinParameter) - int index; - std::string name; -}; - -static const SkinParameter skinParam[] = -{ - {0, "top-left-corner"}, - {0, "standart"}, - {0, "up"}, - {0, "hstart"}, - {0, "in"}, - {0, "normal"}, - {1, "top-edge"}, - {1, "highlighted"}, - {1, "down"}, - {1, "hmiddle"}, - {1, "in-highlighted"}, - {1, "checked"}, - {2, "top-right-corner"}, - {2, "pressed"}, - {2, "left"}, - {2, "hend"}, - {2, "out"}, - {2, "disabled"}, - {3, "left-edge"}, - {3, "disabled"}, - {3, "right"}, - {3, "hgrip"}, - {3, "out-highlighted"}, - {3, "disabled-checked"}, - {4, "bg-quad"}, - {4, "vstart"}, - {4, "normal-highlighted"}, - {5, "right-edge"}, - {5, "vmiddle"}, - {5, "checked-highlighted"}, - {6, "bottom-left-corner"}, - {6, "vend"}, - {7, "bottom-edge"}, - {7, "vgrip"}, - {8, "bottom-right-corner"}, -}; - -static const SkinParameter imageParam[] = -{ - {0, "closeImage"}, - {1, "closeImageHighlighted"}, - {2, "stickyImageUp"}, - {3, "stickyImageDown"}, -}; - -struct SkinHelper final -{ - SkinHelper() : - partType(), - xPos(), - yPos(), - width(), - height(), - rect(), - node(), - image() - { - } - - A_DELETE_COPY(SkinHelper) - - std::string partType; - int xPos; - int yPos; - int width; - int height; - ImageRect *rect; - XmlNodePtr *node; - Image *image; - - bool loadList(const SkinParameter *const params, - const size_t size) A_NONNULL(2) - { - for (size_t f = 0; f < size; f ++) - { - const SkinParameter ¶m = params[f]; - if (partType == param.name) - { - rect->grid[param.index] = Loader::getSubImage( - image, - xPos, yPos, - width, height); - return true; - } - } - return false; - } -}; - -Skin *Theme::readSkin(const std::string &filename, const bool full) -{ - if (filename.empty()) - return nullptr; - - const std::string path = resolveThemePath(filename); - if (!VirtFs::exists(path)) - return nullptr; - XML::Document *const doc = Loader::getXml(path, - UseVirtFs_true, - SkipError_true); - if (doc == nullptr) - return nullptr; - XmlNodeConstPtr rootNode = doc->rootNode(); - if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "skinset")) - { - doc->decRef(); - return nullptr; - } - - const std::string skinSetImage = XML::getProperty(rootNode, "image", ""); - - if (skinSetImage.empty()) - { - logger->log1("Theme::readSkin(): Skinset does not define an image!"); - doc->decRef(); - return nullptr; - } - - Image *const dBorders = Theme::getImageFromTheme(skinSetImage); - ImageRect *const border = new ImageRect; - ImageRect *const images = new ImageRect; - int padding = 3; - int titlePadding = 4; - int titlebarHeight = 0; - int titlebarHeightRelative = 0; - int closePadding = 3; - int stickySpacing = 3; - int stickyPadding = 3; - int resizePadding = 2; - StringIntMap *const mOptions = new StringIntMap; - - // iterate <widget>'s - for_each_xml_child_node(widgetNode, rootNode) - { - if (!xmlNameEqual(widgetNode, "widget")) - continue; - - const std::string widgetType = - XML::getProperty(widgetNode, "type", "unknown"); - if (widgetType == "Window") - { - SkinHelper helper; - const int globalXPos = XML::getProperty(widgetNode, "xpos", 0); - const int globalYPos = XML::getProperty(widgetNode, "ypos", 0); - for_each_xml_child_node(partNode, widgetNode) - { - if (xmlNameEqual(partNode, "part")) - { - helper.partType = XML::getProperty( - partNode, "type", "unknown"); - helper.xPos = XML::getProperty( - partNode, "xpos", 0) + globalXPos; - helper.yPos = XML::getProperty( - partNode, "ypos", 0) + globalYPos; - helper.width = XML::getProperty(partNode, "width", 0); - helper.height = XML::getProperty(partNode, "height", 0); - if ((helper.width == 0) || (helper.height == 0)) - continue; - helper.image = dBorders; - - helper.rect = border; - if (!helper.loadList(skinParam, - sizeof(skinParam) / sizeof(SkinParameter))) - { - helper.rect = images; - helper.loadList(imageParam, - sizeof(imageParam) / sizeof(SkinParameter)); - } - } - else if (full && xmlNameEqual(partNode, "option")) - { - const std::string name = XML::getProperty( - partNode, "name", ""); - if (name == "padding") - { - padding = XML::getProperty(partNode, "value", 3); - } - else if (name == "titlePadding") - { - titlePadding = XML::getProperty(partNode, "value", 4); - } - else if (name == "closePadding") - { - closePadding = XML::getProperty(partNode, "value", 3); - } - else if (name == "stickySpacing") - { - stickySpacing = XML::getProperty(partNode, "value", 3); - } - else if (name == "stickyPadding") - { - stickyPadding = XML::getProperty(partNode, "value", 3); - } - else if (name == "titlebarHeight") - { - titlebarHeight = XML::getProperty( - partNode, "value", 0); - } - else if (name == "titlebarHeightRelative") - { - titlebarHeightRelative = XML::getProperty( - partNode, "value", 0); - } - else if (name == "resizePadding") - { - resizePadding = XML::getProperty( - partNode, "value", 2); - } - else - { - (*mOptions)[name] = XML::getProperty( - partNode, "value", 0); - } - } - } - } - else - { - logger->log("Theme::readSkin(): Unknown widget type '%s'", - widgetType.c_str()); - } - } - - if (dBorders != nullptr) - dBorders->decRef(); - - (*mOptions)["closePadding"] = closePadding; - (*mOptions)["stickyPadding"] = stickyPadding; - (*mOptions)["stickySpacing"] = stickySpacing; - (*mOptions)["titlebarHeight"] = titlebarHeight; - (*mOptions)["titlebarHeightRelative"] = titlebarHeightRelative; - (*mOptions)["resizePadding"] = resizePadding; - - Skin *const skin = new Skin(border, images, filename, "", padding, - titlePadding, mOptions); - delete images; - skin->updateAlpha(mMinimumOpacity); - doc->decRef(); - return skin; -} - -bool Theme::tryThemePath(const std::string &themeName) -{ - if (!themeName.empty()) - { - const std::string path = defaultThemePath + themeName; - if (VirtFs::exists(path)) - { - mThemePath = path; - mThemeName = themeName; - if (theme != nullptr) - theme->loadColors(""); - return true; - } - } - - return false; -} - -void Theme::fillSkinsList(StringVect &list) -{ - VirtFs::getDirs(branding.getStringValue("guiThemePath"), list); - std::sort(list.begin(), list.end()); -} - -void Theme::fillFontsList(StringVect &list) -{ - VirtFs::permitLinks(true); - VirtFs::getFiles(branding.getStringValue("fontsPath"), list); - std::sort(list.begin(), list.end()); - VirtFs::permitLinks(false); -} - -void Theme::fillSoundsList(StringVect &list) -{ - VirtFs::List *const skins = VirtFs::enumerateFiles( - branding.getStringValue("systemsounds")); - - FOR_EACH (StringVectCIter, i, skins->names) - { - if (!VirtFs::isDirectory((branding.getStringValue( - "systemsounds") + *i))) - { - std::string str = *i; - if (findCutLast(str, ".ogg")) - list.push_back(str); - } - } - - VirtFs::freeList(skins); - std::sort(list.begin(), list.end()); -} - -void Theme::selectSkin() -{ - prepareThemePath(); - mScreenDensity = graphicsManager.getDensityString(); -} - -void Theme::prepareThemePath() -{ - initDefaultThemePath(); - - mThemePath.clear(); - mThemeName.clear(); - - // Try theme from settings - if (tryThemePath(config.getStringValue("theme"))) - return; - - // Try theme from branding - if (tryThemePath(branding.getStringValue("theme"))) - return; - - if (mThemePath.empty()) - mThemePath = "graphics/gui"; - - theme->loadColors(mThemePath); - - logger->log("Selected Theme: " + mThemePath); -} - -std::string Theme::resolveThemePath(const std::string &path) -{ - // Need to strip off any dye info for the existence tests - const int pos = CAST_S32(path.find('|')); - std::string file; - if (pos > 0) - file = path.substr(0, pos); - else - file = path; - - // File with path - if (file.find('/') != std::string::npos) - { - // Might be a valid path already - if (VirtFs::exists(file)) - return path; - } - - // Try the theme - file = pathJoin(getThemePath(), file); - - if (VirtFs::exists(file)) - return pathJoin(getThemePath(), path); - - // Backup - return pathJoin(branding.getStringValue("guiPath"), path); -} - -Image *Theme::getImageFromTheme(const std::string &path) -{ - return Loader::getImage(resolveThemePath(path)); -} - -ImageSet *Theme::getImageSetFromTheme(const std::string &path, - const int w, const int h) -{ - return Loader::getImageSet(resolveThemePath(path), w, h); -} - -static int readColorType(const std::string &type) -{ - static const std::string colors[CAST_SIZE( - ThemeColorId::THEME_COLORS_END)] = - { - "BROWSERBOX", - "BROWSERBOX_OUTLINE", - "SELFNICK", - "SELFNICK_OUTLINE", - "TEXT", - "TEXT_OUTLINE", - "CARET", - "SHADOW", - "OUTLINE", - "BORDER", - "PROGRESS_BAR", - "PROGRESS_BAR_OUTLINE", - "BUTTON", - "BUTTON_OUTLINE", - "BUTTON_DISABLED", - "BUTTON_DISABLED_OUTLINE", - "BUTTON_HIGHLIGHTED", - "BUTTON_HIGHLIGHTED_OUTLINE", - "BUTTON_PRESSED", - "BUTTON_PRESSED_OUTLINE", - "CHECKBOX", - "CHECKBOX_OUTLINE", - "DROPDOWN", - "DROPDOWN_OUTLINE", - "LABEL", - "LABEL_OUTLINE", - "LISTBOX", - "LISTBOX_OUTLINE", - "LISTBOX_SELECTED", - "LISTBOX_SELECTED_OUTLINE", - "RADIOBUTTON", - "RADIOBUTTON_OUTLINE", - "POPUP", - "POPUP_OUTLINE", - "TAB", - "TAB_OUTLINE", - "TAB_HIGHLIGHTED", - "TAB_HIGHLIGHTED_OUTLINE", - "TAB_SELECTED", - "TAB_SELECTED_OUTLINE", - "TEXTBOX", - "TEXTFIELD", - "TEXTFIELD_OUTLINE", - "WINDOW", - "WINDOW_OUTLINE", - "BATTLE_CHAT_TAB", - "BATTLE_CHAT_TAB_OUTLINE", - "CHANNEL_CHAT_TAB", - "CHANNEL_CHAT_TAB_OUTLINE", - "PARTY_CHAT_TAB", - "PARTY_CHAT_TAB_OUTLINE", - "PARTY_SOCIAL_TAB", - "PARTY_SOCIAL_TAB_OUTLINE", - "GUILD_CHAT_TAB", - "GUILD_CHAT_TAB_OUTLINE", - "GUILD_SOCIAL_TAB", - "GUILD_SOCIAL_TAB_OUTLINE", - "GM_CHAT_TAB", - "GM_CHAT_TAB_OUTLINE", - "BATTLE_CHAT_TAB_HIGHLIGHTED", - "BATTLE_CHAT_TAB_HIGHLIGHTED_OUTLINE", - "CHANNEL_CHAT_TAB_HIGHLIGHTED", - "CHANNEL_CHAT_TAB_HIGHLIGHTED_OUTLINE", - "PARTY_CHAT_TAB_HIGHLIGHTED", - "PARTY_CHAT_TAB_HIGHLIGHTED_OUTLINE", - "PARTY_SOCIAL_TAB_HIGHLIGHTED", - "PARTY_SOCIAL_TAB_HIGHLIGHTED_OUTLINE", - "GUILD_CHAT_TAB_HIGHLIGHTED", - "GUILD_CHAT_TAB_HIGHLIGHTED_OUTLINE", - "GUILD_SOCIAL_TAB_HIGHLIGHTED", - "GUILD_SOCIAL_TAB_HIGHLIGHTED_OUTLINE", - "GM_CHAT_TAB_HIGHLIGHTED", - "GM_CHAT_TAB_HIGHLIGHTED_OUTLINE", - "BATTLE_CHAT_TAB_SELECTED", - "BATTLE_CHAT_TAB_SELECTED_OUTLINE", - "CHANNEL_CHAT_TAB_SELECTED", - "CHANNEL_CHAT_TAB_SELECTED_OUTLINE", - "PARTY_CHAT_TAB_SELECTED", - "PARTY_CHAT_TAB_SELECTED_OUTLINE", - "PARTY_SOCIAL_TAB_SELECTED", - "PARTY_SOCIAL_TAB_SELECTED_OUTLINE", - "GUILD_CHAT_TAB_SELECTED", - "GUILD_CHAT_TAB_SELECTED_OUTLINE", - "GUILD_SOCIAL_TAB_SELECTED", - "GUILD_SOCIAL_TAB_SELECTED_OUTLINE", - "GM_CHAT_TAB_SELECTED", - "GM_CHAT_TAB_SELECTED_OUTLINE", - "BACKGROUND", - "BACKGROUND_GRAY", - "SCROLLBAR_GRAY", - "DROPDOWN_SHADOW", - "HIGHLIGHT", - "HIGHLIGHT_OUTLINE", - "TAB_FLASH", - "TAB_FLASH_OUTLINE", - "TAB_PLAYER_FLASH", - "TAB_PLAYER_FLASH_OUTLINE", - "SHOP_WARNING", - "ITEM_EQUIPPED", - "ITEM_EQUIPPED_OUTLINE", - "ITEM_NOT_EQUIPPED", - "ITEM_NOT_EQUIPPED_OUTLINE", - "CHAT", - "CHAT_OUTLINE", - "GM", - "GM_OUTLINE", - "GLOBAL", - "GLOBAL_OUTLINE", - "PLAYER", - "PLAYER_OUTLINE", - "WHISPER_TAB", - "WHISPER_TAB_OUTLINE", - "WHISPER_TAB_OFFLINE", - "WHISPER_TAB_OFFLINE_OUTLINE", - "WHISPER_TAB_HIGHLIGHTED", - "WHISPER_TAB_HIGHLIGHTED_OUTLINE", - "WHISPER_TAB_OFFLINE_HIGHLIGHTED", - "WHISPER_TAB_OFFLINE_HIGHLIGHTED_OUTLINE", - "WHISPER_TAB_SELECTED", - "WHISPER_TAB_SELECTED_OUTLINE", - "WHISPER_TAB_OFFLINE_SELECTED", - "WHISPER_TAB_OFFLINE_SELECTED_OUTLINE", - "IS", - "IS_OUTLINE", - "SERVER", - "SERVER_OUTLINE", - "LOGGER", - "LOGGER_OUTLINE", - "HYPERLINK", - "HYPERLINK_OUTLINE", - "UNKNOWN_ITEM", - "UNKNOWN_ITEM_OUTLINE", - "GENERIC", - "GENERIC_OUTLINE", - "HEAD", - "HEAD_OUTLINE", - "USABLE", - "USABLE_OUTLINE", - "TORSO", - "TORSO_OUTLINE", - "ONEHAND", - "ONEHAND_OUTLINE", - "LEGS", - "LEGS_OUTLINE", - "FEET", - "FEET_OUTLINE", - "TWOHAND", - "TWOHAND_OUTLINE", - "SHIELD", - "SHIELD_OUTLINE", - "RING", - "RING_OUTLINE", - "NECKLACE", - "NECKLACE_OUTLINE", - "ARMS", - "ARMS_OUTLINE", - "AMMO", - "AMMO_OUTLINE", - "SERVER_VERSION_NOT_SUPPORTED", - "SERVER_VERSION_NOT_SUPPORTED_OUTLINE", - "WARNING", - "WARNING_OUTLINE", - "CHARM", - "CHARM_OUTLINE", - "CARD", - "CARD_OUTLINE", - "PLAYER_ADVANCED", - "PLAYER_ADVANCED_OUTLINE", - "BUBBLE_NAME", - "BUBBLE_NAME_OUTLINE", - "BUBBLE_TEXT", - "BUBBLE_TEXT_OUTLINE", - "BLACK", - "BLACK_OUTLINE", - "RED", - "RED_OUTLINE", - "GREEN", - "GREEN_OUTLINE", - "BLUE", - "BLUE_OUTLINE", - "ORANGE", - "ORANGE_OUTLINE", - "YELLOW", - "YELLOW_OUTLINE", - "PINK", - "PINK_OUTLINE", - "PURPLE", - "PURPLE_OUTLINE", - "GRAY", - "GRAY_OUTLINE", - "BROWN", - "BROWN_OUTLINE", - "STATUSBAR_ON", - "STATUSBAR_OFF", - "TABLE_BACKGROUND", - "SLOTS_BAR", - "SLOTS_BAR_OUTLINE", - "HP_BAR", - "HP_BAR_OUTLINE", - "MP_BAR", - "MP_BAR_OUTLINE", - "NO_MP_BAR", - "NO_MP_BAR_OUTLINE", - "XP_BAR", - "XP_BAR_OUTLINE", - "WEIGHT_BAR", - "WEIGHT_BAR_OUTLINE", - "MONEY_BAR", - "MONEY_BAR_OUTLINE", - "ARROWS_BAR", - "ARROWS_BAR_OUTLINE", - "STATUS_BAR", - "STATUS_BAR_OUTLINE", - "JOB_BAR", - "JOB_BAR_OUTLINE", - "OLDCHAT", - "OLDCHAT_OUTLINE", - "AWAYCHAT", - "AWAYCHAT_OUTLINE", - "SKILL_COOLDOWN", - "TEXT_DISABLED", - "TEXT_DISABLED_OUTLINE" - }; - - if (type.empty()) - return -1; - - for (int i = 0; i < CAST_S32(ThemeColorId::THEME_COLORS_END); i++) - { - if (compareStrI(type, colors[i]) == 0) - return i; - } - - return -1; -} - -static Color readColor(const std::string &description) -{ - const int size = static_cast<int>(description.length()); - if (size < 7 || description[0] != '#') - { - logger->log("Error, invalid theme color palette: %s", - description.c_str()); - return Palette::BLACK; - } - - unsigned int v = 0; - for (int i = 1; i < 7; ++i) - { - signed const char c = description[i]; - int n; - - if ('0' <= c && c <= '9') - { - n = c - '0'; - } - else if ('A' <= c && c <= 'F') - { - n = c - 'A' + 10; - } - else if ('a' <= c && c <= 'f') - { - n = c - 'a' + 10; - } - else - { - logger->log("Error, invalid theme color palette: %s", - description.c_str()); - return Palette::BLACK; - } - - v = (v << 4) | n; - } - - return Color(v); -} - -static GradientTypeT readColorGradient(const std::string &grad) -{ - static const std::string grads[] = - { - "STATIC", - "PULSE", - "SPECTRUM", - "RAINBOW" - }; - - if (grad.empty()) - return GradientType::STATIC; - - for (int i = 0; i < 4; i++) - { - if (compareStrI(grad, grads[i]) != 0) - return static_cast<GradientTypeT>(i); - } - - return GradientType::STATIC; -} - -static int readProgressType(const std::string &type) -{ - static const std::string colors[CAST_SIZE( - ProgressColorId::THEME_PROG_END)] = - { - "HP", - "HP_POISON", - "MP", - "NO_MP", - "EXP", - "INVY_SLOTS", - "WEIGHT", - "JOB", - "UPDATE", - "MONEY", - "ARROWS", - "STATUS" - }; - - if (type.empty()) - return -1; - - for (int i = 0; i < CAST_S32(ProgressColorId::THEME_PROG_END); i++) - { - if (compareStrI(type, colors[i]) == 0) - return i; - } - - return -1; -} - -void Theme::loadColors(std::string file) -{ - if (file.empty()) - file = "colors.xml"; - else - file = pathJoin(file, "colors.xml"); - - XML::Document *const doc = Loader::getXml(resolveThemePath(file), - UseVirtFs_true, - SkipError_false); - if (doc == nullptr) - return; - XmlNodeConstPtrConst root = doc->rootNode(); - - if ((root == nullptr) || !xmlNameEqual(root, "colors")) - { - logger->log("Error loading colors file: %s", file.c_str()); - doc->decRef(); - return; - } - - logger->log("Loading colors file: %s", file.c_str()); - - for_each_xml_child_node(paletteNode, root) - { - if (xmlNameEqual(paletteNode, "progressbar")) - { - const int type = readProgressType(XML::getProperty( - paletteNode, "id", "")); - if (type < 0) - continue; - - mProgressColors[type] = new DyePalette(XML::getProperty( - paletteNode, "color", ""), 6); - } - else if (!xmlNameEqual(paletteNode, "palette")) - { - continue; - } - - const int paletteId = XML::getProperty(paletteNode, "id", 1); - if (paletteId < 0 || paletteId >= THEME_PALETTES) - continue; - - for_each_xml_child_node(node, paletteNode) - { - if (xmlNameEqual(node, "color")) - { - const std::string id = XML::getProperty(node, "id", ""); - const int type = readColorType(id); - if (type < 0) - continue; - - const std::string temp = XML::getProperty(node, "color", ""); - if (temp.empty()) - continue; - - const Color color = readColor(temp); - const GradientTypeT grad = readColorGradient( - XML::getProperty(node, "effect", "")); - mColors[paletteId * CAST_SIZE( - ThemeColorId::THEME_COLORS_END) + type].set( - type, color, grad, 10); - - if (!findLast(id, "_OUTLINE")) - { - const int type2 = readColorType(id + "_OUTLINE"); - if (type2 < 0) - continue; - const int idx = paletteId - * CAST_S32(ThemeColorId::THEME_COLORS_END); - mColors[idx + type2] = mColors[idx + type]; - } - } - } - } - doc->decRef(); -} - -#define loadGrid() \ - { \ - const ImageRect &rect = skin->getBorder(); \ - for (int f = start; f <= end; f ++) \ - { \ - if (rect.grid[f]) \ - { \ - image.grid[f] = rect.grid[f]; \ - image.grid[f]->incRef(); \ - } \ - } \ - } - -void Theme::loadRect(ImageRect &image, - const std::string &name, - const std::string &name2, - const int start, - const int end) -{ - Skin *const skin = load(name, name2, false); - if (skin != nullptr) - { - loadGrid(); - unload(skin); - } -} - -Skin *Theme::loadSkinRect(ImageRect &image, - const std::string &name, - const std::string &name2, - const int start, - const int end) -{ - Skin *const skin = load(name, name2); - if (skin != nullptr) - loadGrid(); - return skin; -} - -void Theme::unloadRect(const ImageRect &rect, - const int start, - const int end) -{ - for (int f = start; f <= end; f ++) - { - if (rect.grid[f] != nullptr) - rect.grid[f]->decRef(); - } -} - -Image *Theme::getImageFromThemeXml(const std::string &name, - const std::string &name2) -{ - if (theme == nullptr) - return nullptr; - - Skin *const skin = theme->load(name, name2, false); - if (skin != nullptr) - { - const ImageRect &rect = skin->getBorder(); - if (rect.grid[0] != nullptr) - { - Image *const image = rect.grid[0]; - image->incRef(); - theme->unload(skin); - return image; - } - theme->unload(skin); - } - return nullptr; -} - -ImageSet *Theme::getImageSetFromThemeXml(const std::string &name, - const std::string &name2, - const int w, const int h) -{ - if (theme == nullptr) - return nullptr; - - Skin *const skin = theme->load(name, name2, false); - if (skin != nullptr) - { - const ImageRect &rect = skin->getBorder(); - if (rect.grid[0] != nullptr) - { - Image *const image = rect.grid[0]; - const SDL_Rect &rect2 = image->mBounds; - if ((rect2.w != 0u) && (rect2.h != 0u)) - { - ImageSet *const imageSet = Loader::getSubImageSet( - image, w, h); - theme->unload(skin); - return imageSet; - } - } - theme->unload(skin); - } - return nullptr; -} - -#define readValue(name) \ - { \ - tmpData = reinterpret_cast<XmlChar*>( \ - XmlNodeGetContent(infoNode)); \ - info->name = tmpData; \ - XmlFree(tmpData); \ - } - -#define readIntValue(name) \ - { \ - tmpData = reinterpret_cast<XmlChar*>( \ - XmlNodeGetContent(infoNode)); \ - info->name = atoi(tmpData); \ - XmlFree(tmpData); \ - } - -#define readFloatValue(name) \ - { \ - tmpData = reinterpret_cast<XmlChar*>( \ - XmlNodeGetContent(infoNode)); \ - info->name = static_cast<float>(atof(tmpData)); \ - XmlFree(tmpData); \ - } - -ThemeInfo *Theme::loadInfo(const std::string &themeName) -{ - std::string path; - if (themeName.empty()) - { - path = "graphics/gui/info.xml"; - } - else - { - path = pathJoin(defaultThemePath, - themeName, - "info.xml"); - } - logger->log("loading: " + path); - XML::Document *const doc = Loader::getXml(path, - UseVirtFs_true, - SkipError_false); - if (doc == nullptr) - return nullptr; - XmlNodeConstPtrConst rootNode = doc->rootNode(); - - if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "info")) - { - doc->decRef(); - return nullptr; - } - - ThemeInfo *const info = new ThemeInfo; - - const std::string fontSize2("fontSize_" + mScreenDensity); - const std::string npcfontSize2("npcfontSize_" + mScreenDensity); - XmlChar *tmpData = nullptr; - for_each_xml_child_node(infoNode, rootNode) - { - if (xmlNameEqual(infoNode, "name")) - readValue(name) - else if (xmlNameEqual(infoNode, "copyright")) - readValue(copyright) - else if (xmlNameEqual(infoNode, "font")) - readValue(font) - else if (xmlNameEqual(infoNode, "boldFont")) - readValue(boldFont) - else if (xmlNameEqual(infoNode, "particleFont")) - readValue(particleFont) - else if (xmlNameEqual(infoNode, "helpFont")) - readValue(helpFont) - else if (xmlNameEqual(infoNode, "secureFont")) - readValue(secureFont) - else if (xmlNameEqual(infoNode, "npcFont")) - readValue(npcFont) - else if (xmlNameEqual(infoNode, "japanFont")) - readValue(japanFont) - else if (xmlNameEqual(infoNode, "chinaFont")) - readValue(chinaFont) - else if (xmlNameEqual(infoNode, "fontSize")) - readIntValue(fontSize) - else if (xmlNameEqual(infoNode, "npcfontSize")) - readIntValue(npcfontSize) - else if (xmlNameEqual(infoNode, "guialpha")) - readFloatValue(guiAlpha) - else if (xmlNameEqual(infoNode, fontSize2.c_str())) - readIntValue(fontSize) - else if (xmlNameEqual(infoNode, npcfontSize2.c_str())) - readIntValue(npcfontSize) - } - doc->decRef(); - return info; -} - -ThemeColorIdT Theme::getIdByChar(const signed char c, bool &valid) const -{ - const CharColors::const_iterator it = mCharColors.find(c); - if (it != mCharColors.end()) - { - valid = true; - return static_cast<ThemeColorIdT>((*it).second); - } - - valid = false; - return ThemeColorId::BROWSERBOX; -} |