00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "gui/skin.h"
00025
00026 #include "configuration.h"
00027 #include "configlistener.h"
00028 #include "log.h"
00029
00030 #include "resources/image.h"
00031 #include "resources/resourcemanager.h"
00032
00033 #include "utils/dtor.h"
00034 #include "utils/strprintf.h"
00035 #include "utils/xml.h"
00036
00037 #include <algorithm>
00038
00039 SkinLoader *SkinLoader::mInstance = 0;
00040
00041
00042 class SkinConfigListener : public ConfigListener
00043 {
00044 public:
00045 SkinConfigListener(SkinLoader *skinLoader)
00046 : mSkinLoader(skinLoader)
00047 {
00048 config.addListener("guialpha", this);
00049 }
00050
00051 ~SkinConfigListener()
00052 {
00053 config.removeListener("guialpha", this);
00054 }
00055
00056 void optionChanged(const std::string &)
00057 {
00058 mSkinLoader->updateAlpha();
00059 }
00060
00061 private:
00062 SkinLoader *mSkinLoader;
00063 };
00064
00065
00066 Skin::Skin(ImageRect skin, Image *close, Image *stickyUp, Image *stickyDown,
00067 const std::string &filePath,
00068 const std::string &name):
00069 instances(0),
00070 mFilePath(filePath),
00071 mName(name),
00072 mBorder(skin),
00073 mCloseImage(close),
00074 mStickyImageUp(stickyUp),
00075 mStickyImageDown(stickyDown)
00076 {
00077 }
00078
00079 Skin::~Skin()
00080 {
00081
00082 for (int i = 0; i < 9; i++)
00083 delete mBorder.grid[i];
00084
00085 mCloseImage->decRef();
00086 delete mStickyImageUp;
00087 delete mStickyImageDown;
00088 }
00089
00090 void Skin::updateAlpha()
00091 {
00092 const float alpha = config.getValue("guialpha", 0.8);
00093
00094 for_each(mBorder.grid, mBorder.grid + 9,
00095 std::bind2nd(std::mem_fun(&Image::setAlpha), alpha));
00096
00097 mCloseImage->setAlpha(alpha);
00098 mStickyImageUp->setAlpha(alpha);
00099 mStickyImageDown->setAlpha(alpha);
00100 }
00101
00102 int Skin::getMinWidth() const
00103 {
00104 return (mBorder.grid[ImageRect::UPPER_LEFT]->getWidth() +
00105 mBorder.grid[ImageRect::UPPER_CENTER]->getWidth()) +
00106 mBorder.grid[ImageRect::UPPER_RIGHT]->getWidth();
00107 }
00108
00109 int Skin::getMinHeight() const
00110 {
00111 return (mBorder.grid[ImageRect::UPPER_LEFT]->getHeight() +
00112 mBorder.grid[ImageRect::LEFT]->getHeight()) +
00113 mBorder.grid[ImageRect::LOWER_LEFT]->getHeight();
00114 }
00115
00116 SkinLoader::SkinLoader()
00117 : mSkinConfigListener(new SkinConfigListener(this))
00118 {
00119 }
00120
00121 SkinLoader::~SkinLoader()
00122 {
00123 delete_all(mSkins);
00124 delete mSkinConfigListener;
00125 }
00126
00127 SkinLoader *SkinLoader::instance()
00128 {
00129 if (!mInstance)
00130 mInstance = new SkinLoader;
00131
00132 return mInstance;
00133 }
00134
00135 void SkinLoader::deleteInstance()
00136 {
00137 delete mInstance;
00138 mInstance = 0;
00139 }
00140
00141 Skin *SkinLoader::load(const std::string &filename,
00142 const std::string &defaultPath)
00143 {
00144
00145 SkinIterator skinIterator = mSkins.find(filename);
00146 if (mSkins.end() != skinIterator)
00147 {
00148 skinIterator->second->instances++;
00149 return skinIterator->second;
00150 }
00151
00152 Skin *skin = readSkin(filename);
00153
00154 if (!skin)
00155 {
00156
00157 if (filename != defaultPath)
00158 {
00159 logger->log("Error loading skin '%s', falling back on default.",
00160 filename.c_str());
00161
00162 skin = readSkin(defaultPath);
00163 }
00164
00165 if (!skin)
00166 {
00167 logger->error(strprintf("Error: Loading default skin '%s' failed. "
00168 "Make sure the skin file is valid.",
00169 defaultPath.c_str()));
00170 }
00171 }
00172
00173
00174 mSkins[filename] = skin;
00175
00176 return skin;
00177 }
00178
00179 void SkinLoader::updateAlpha()
00180 {
00181 for (SkinIterator iter = mSkins.begin(); iter != mSkins.end(); ++iter)
00182 iter->second->updateAlpha();
00183 }
00184
00185 Skin *SkinLoader::readSkin(const std::string &filename)
00186 {
00187 if (filename.empty())
00188 return 0;
00189
00190 logger->log("Loading skin '%s'.", filename.c_str());
00191
00192 XML::Document doc(filename);
00193 xmlNodePtr rootNode = doc.rootNode();
00194
00195 if (!rootNode || !xmlStrEqual(rootNode->name, BAD_CAST "skinset"))
00196 return 0;
00197
00198 const std::string skinSetImage = XML::getProperty(rootNode, "image", "");
00199
00200 if (skinSetImage.empty())
00201 {
00202 logger->log("SkinLoader::readSkin(): Skinset does not define an "
00203 "image!");
00204 return 0;
00205 }
00206
00207 logger->log("SkinLoader::load(): <skinset> defines "
00208 "'%s' as a skin image.", skinSetImage.c_str());
00209
00210 ResourceManager *resman = ResourceManager::getInstance();
00211 Image *dBorders = resman->getImage("graphics/gui/" + skinSetImage);
00212 ImageRect border;
00213
00214
00215 for_each_xml_child_node(widgetNode, rootNode)
00216 {
00217 if (!xmlStrEqual(widgetNode->name, BAD_CAST "widget"))
00218 continue;
00219
00220 const std::string widgetType =
00221 XML::getProperty(widgetNode, "type", "unknown");
00222 if (widgetType == "Window")
00223 {
00224
00225
00226
00227
00228 for_each_xml_child_node(partNode, widgetNode)
00229 {
00230 if (!xmlStrEqual(partNode->name, BAD_CAST "part"))
00231 continue;
00232
00233 const std::string partType =
00234 XML::getProperty(partNode, "type", "unknown");
00235
00236 const int xPos = XML::getProperty(partNode, "xpos", 0);
00237 const int yPos = XML::getProperty(partNode, "ypos", 0);
00238 const int width = XML::getProperty(partNode, "width", 1);
00239 const int height = XML::getProperty(partNode, "height", 1);
00240
00241 if (partType == "top-left-corner")
00242 border.grid[0] = dBorders->getSubImage(xPos, yPos, width, height);
00243 else if (partType == "top-edge")
00244 border.grid[1] = dBorders->getSubImage(xPos, yPos, width, height);
00245 else if (partType == "top-right-corner")
00246 border.grid[2] = dBorders->getSubImage(xPos, yPos, width, height);
00247
00248
00249 else if (partType == "left-edge")
00250 border.grid[3] = dBorders->getSubImage(xPos, yPos, width, height);
00251 else if (partType == "bg-quad")
00252 border.grid[4] = dBorders->getSubImage(xPos, yPos, width, height);
00253 else if (partType == "right-edge")
00254 border.grid[5] = dBorders->getSubImage(xPos, yPos, width, height);
00255
00256
00257 else if (partType == "bottom-left-corner")
00258 border.grid[6] = dBorders->getSubImage(xPos, yPos, width, height);
00259 else if (partType == "bottom-edge")
00260 border.grid[7] = dBorders->getSubImage(xPos, yPos, width, height);
00261 else if (partType == "bottom-right-corner")
00262 border.grid[8] = dBorders->getSubImage(xPos, yPos, width, height);
00263
00264 else
00265 logger->log("SkinLoader::readSkin(): Unknown part type '%s'",
00266 partType.c_str());
00267 }
00268 }
00269 else
00270 {
00271 logger->log("SkinLoader::readSkin(): Unknown widget type '%s'",
00272 widgetType.c_str());
00273 }
00274 }
00275
00276 dBorders->decRef();
00277
00278 logger->log("Finished loading skin.");
00279
00280
00281 Image *closeImage = resman->getImage("graphics/gui/close_button.png");
00282 Image *sticky = resman->getImage("graphics/gui/sticky_button.png");
00283 Image *stickyImageUp = sticky->getSubImage(0, 0, 15, 15);
00284 Image *stickyImageDown = sticky->getSubImage(15, 0, 15, 15);
00285 sticky->decRef();
00286
00287 Skin *skin = new Skin(border, closeImage, stickyImageUp, stickyImageDown,
00288 filename);
00289 skin->updateAlpha();
00290 return skin;
00291 }