theme.cpp

Go to the documentation of this file.
00001 /* $Id: theme.cpp 24834 2008-03-19 16:04:41Z brunowolff $ */
00002 /*
00003    Copyright (C) 2003 - 2008 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 //! @file theme.cpp
00016 //!
00017 
00018 #include "global.hpp"
00019 
00020 #include "config.hpp"
00021 #include "font.hpp"
00022 #include "gettext.hpp"
00023 #include "language.hpp"
00024 #include "log.hpp"
00025 #include "sdl_utils.hpp"
00026 #include "theme.hpp"
00027 #include "util.hpp"
00028 #include "serialization/string_utils.hpp"
00029 #include "wml_exception.hpp"
00030 
00031 #include <cassert>
00032 #include <cstdlib>
00033 #include <sstream>
00034 
00035 #define DBG_DP LOG_STREAM(debug, display)
00036 #define LOG_DP LOG_STREAM(info, display)
00037 #define ERR_DP LOG_STREAM(err, display)
00038 
00039 namespace {
00040     const int XDim = 1024;
00041     const int YDim = 768;
00042 
00043     const size_t DefaultFontSize = font::SIZE_NORMAL;
00044         const Uint32 DefaultFontRGB = 0x00C8C8C8;
00045 
00046     _rect ref_rect = { 0, 0, 0, 0 };
00047 }
00048 
00049 static size_t compute(std::string expr, size_t ref1, size_t ref2=0 ) {
00050         size_t ref = 0;
00051         if (expr[0] == '=') {
00052           ref = ref1;
00053           expr = expr.substr(1);
00054         } else if ((expr[0] == '+') || (expr[0] == '-')) {
00055           ref = ref2;
00056         }
00057 
00058         return ref + atoi(expr.c_str());
00059     }
00060 
00061     // If x2 or y2 are not specified, use x1 and y1 values
00062 static _rect read_rect(const config& cfg) {
00063         _rect rect = { 0, 0, 0, 0 };
00064         const std::vector<std::string> items = utils::split(cfg["rect"].c_str());
00065         if(items.size() >= 1)
00066             rect.x1 = atoi(items[0].c_str());
00067 
00068         if(items.size() >= 2)
00069             rect.y1 = atoi(items[1].c_str());
00070 
00071         if(items.size() >= 3)
00072             rect.x2 = atoi(items[2].c_str());
00073         else
00074             rect.x2 = rect.x1;
00075 
00076         if(items.size() >= 4)
00077             rect.y2 = atoi(items[3].c_str());
00078         else
00079             rect.y2 = rect.y1;
00080 
00081         return rect;
00082     }
00083 
00084 static SDL_Rect read_sdl_rect(const config& cfg) {
00085         SDL_Rect sdlrect;
00086         const _rect rect = read_rect(cfg);
00087         sdlrect.x = rect.x1;
00088         sdlrect.y = rect.y1;
00089         sdlrect.w = (rect.x2 > rect.x1) ? (rect.x2 - rect.x1) : 0;
00090         sdlrect.h = (rect.y2 > rect.y1) ? (rect.y2 - rect.y1) : 0;
00091 
00092         return sdlrect;
00093     }
00094 
00095 static std::string resolve_rect(const std::string& rect_str) {
00096         _rect rect = { 0, 0, 0, 0 };
00097         std::stringstream resolved;
00098         const std::vector<std::string> items = utils::split(rect_str.c_str());
00099         if(items.size() >= 1) {
00100             rect.x1 = compute(items[0], ref_rect.x1, ref_rect.x2);
00101             resolved << rect.x1;
00102         }
00103         if(items.size() >= 2) {
00104             rect.y1 = compute(items[1], ref_rect.y1, ref_rect.y2);
00105             resolved << "," << rect.y1;
00106         }
00107         if(items.size() >= 3) {
00108             rect.x2 = compute(items[2], ref_rect.x2, rect.x1);
00109             resolved << "," << rect.x2;
00110         }
00111         if(items.size() >= 4) {
00112             rect.y2 = compute(items[3], ref_rect.y2, rect.y1);
00113             resolved << "," << rect.y2;
00114         }
00115 
00116         // DBG_DP << "Rect " << rect_str << "\t: " << resolved.str() << "\n";
00117 
00118         ref_rect = rect;
00119         return resolved.str();
00120     }
00121 
00122 namespace {
00123     config empty_config = config();
00124 }
00125 
00126 static config& find_ref(const std::string& id, config& cfg, bool remove = false) {
00127         for(config::child_map::const_iterator i = cfg.all_children().begin();
00128             i != cfg.all_children().end(); i++) {
00129             for (config::child_list::const_iterator j = i->second.begin();
00130                  j != i->second.end(); j++) {
00131                 if ((**j)["id"] == id) {
00132                     //DBG_DP << "Found a " << *(*i).first << "\n";
00133                     if (remove) {
00134                         const config* const res = cfg.find_child((*i).first,"id",id);
00135                         const size_t index = std::find((*i).second.begin(), (*i).second.end(),
00136                                            res) - (*i).second.begin();
00137                         cfg.remove_child((*i).first,index);
00138                         return empty_config;
00139                     } else {
00140                         return **j;
00141                     }
00142                 }
00143 
00144                 // recursively look in children
00145                 config& c = find_ref(id, **j, remove);
00146                 if (!c["id"].empty()) {
00147                     return c;
00148                 }
00149             }
00150         }
00151         // not found
00152         return empty_config;
00153     }
00154 
00155 #ifdef DEBUG
00156     // to be called from gdb
00157     config& find_ref(const char* id, config& cfg) {
00158         return find_ref(std::string(id),cfg);
00159     }
00160 #endif
00161 
00162 static void expand_partialresolution(config& dst_cfg, const config& top_cfg)
00163     {
00164         std::vector<config> res_cfgs_;
00165         // resolve all the partialresolutions
00166         const config::child_list& parts_list = top_cfg.get_children("partialresolution");
00167         for(config::child_list::const_iterator i = parts_list.begin(); i != parts_list.end(); ++i) {
00168             // follow the inheritance hierarchy and push all the nodes on the stack
00169             std::vector<const config*> parent_stack(1, (*i));
00170             const config* parent;
00171             const t_string* parent_id = &((**i)["inherits"]);
00172             while((parent = top_cfg.find_child("resolution", "id", (*parent_id))) == NULL) {
00173                 parent = top_cfg.find_child("partialresolution", "id", (*parent_id));
00174                 if(parent == NULL)
00175                     throw config::error("[partialresolution] refers to non-existant [resolution] " + (*parent_id).str());
00176                 parent_stack.push_back(parent);
00177                 parent_id = &((*parent)["inherits"]);
00178             }
00179 
00180             // Add the parent resolution and apply all the modifications of its children
00181             res_cfgs_.push_back(*parent);
00182             while(!parent_stack.empty()) {
00183                 //override attributes
00184                 for(string_map::const_iterator j = parent_stack.back()->values.begin(); j != parent_stack.back()->values.end(); ++j) {
00185                     res_cfgs_.back().values[j->first] = j->second;
00186                 }
00187 
00188                 {
00189                     const config::child_list& c = parent_stack.back()->get_children("remove");
00190                     for(config::child_list::const_iterator j = c.begin(); j != c.end(); ++j) {
00191                         find_ref ((**j)["id"], res_cfgs_.back(), true);
00192                     }
00193                 }
00194                 {
00195                     const config::child_list& c = parent_stack.back()->get_children("change");
00196                     for(config::child_list::const_iterator j = c.begin(); j != c.end(); ++j) {
00197                         config& target = find_ref ((**j)["id"], res_cfgs_.back());
00198                         for(string_map::iterator k = (**j).values.begin();
00199                                 k != (**j).values.end(); ++k) {
00200                             target.values[k->first] = k->second;
00201                         }
00202                     }
00203                 }
00204                 {
00205                     // cannot add [status] sub-elements, but who cares
00206                     const config* c = parent_stack.back()->child("add");
00207                     if (c != NULL) {
00208                         const config::child_map m = c->all_children();
00209                         for(config::child_map::const_iterator j = m.begin(); j != m.end(); ++j) {
00210                             for(config::child_list::const_iterator k = j->second.begin();
00211                                     k != j->second.end(); ++k) {
00212                                 res_cfgs_.back().add_child(j->first, **k);
00213                             }
00214                         }
00215                     }
00216                 }
00217                 parent_stack.pop_back();
00218             }
00219         }
00220         // Add all the resolutions
00221         const config::child_list& res_list = top_cfg.get_children("resolution");
00222         for(config::child_list::const_iterator j = res_list.begin(); j != res_list.end(); ++j) {
00223             dst_cfg.add_child("resolution", (**j));
00224         }
00225         // Add all the resolved resolutions
00226         for(std::vector<config>::const_iterator k = res_cfgs_.begin(); k != res_cfgs_.end(); ++k) {
00227             dst_cfg.add_child("resolution", (*k));
00228         }
00229         return;
00230     }
00231 
00232 static void do_resolve_rects(const config& cfg, config& resolved_config, config* resol_cfg = NULL) {
00233 
00234         // recursively resolve children
00235         for(config::all_children_iterator i = cfg.ordered_begin(); i != cfg.ordered_end(); ++i) {
00236             const std::pair<const std::string*,const config*>& value = *i;
00237             config& childcfg = resolved_config.add_child(*value.first);
00238             do_resolve_rects(*value.second, childcfg, (*value.first =="resolution") ? &childcfg : resol_cfg);
00239         }
00240 
00241         // copy all key/values
00242         for(string_map::const_iterator j = cfg.values.begin(); j != cfg.values.end(); ++j) {
00243             resolved_config.values[j->first] = j->second;
00244         }
00245 
00246         // override default reference rect with "ref" parameter if any
00247         if (!cfg["ref"].empty()) {
00248             if (resol_cfg == NULL) {
00249                 ERR_DP << "Use of ref= outside a [resolution] block\n";
00250             } else {
00251                 //DBG_DP << ">> Looking for " << cfg["ref"] << "\n";
00252                 const config ref = find_ref (cfg["ref"], *resol_cfg);
00253 
00254                 if (ref["id"].empty()) {
00255                     ERR_DP << "Reference to non-existent rect id \"" << cfg["ref"] << "\"\n";
00256                 } else if (ref["rect"].empty()) {
00257                     ERR_DP << "Reference to id \"" << cfg["ref"] <<
00258                         "\" which does not have a \"rect\"\n";
00259                 } else {
00260                     ref_rect = read_rect(ref);
00261                 }
00262             }
00263         }
00264         // resolve the rect value to absolute coordinates
00265         if (!cfg["rect"].empty()) {
00266             resolved_config.values["rect"] = resolve_rect(cfg["rect"]);
00267         }
00268     }
00269 
00270 theme::object::object() : location_modified_(false), loc_(empty_rect), relative_loc_(empty_rect),
00271                           last_screen_(empty_rect), xanchor_(object::FIXED), yanchor_(object::FIXED)
00272 {
00273 }
00274 
00275 theme::object::object(const config& cfg) :
00276         location_modified_(false), id_(cfg["id"]), loc_(read_sdl_rect(cfg)),
00277         relative_loc_(empty_rect), last_screen_(empty_rect),
00278         xanchor_(read_anchor(cfg["xanchor"])), yanchor_(read_anchor(cfg["yanchor"]))
00279 {
00280 }
00281 
00282 theme::tborder::tborder() :
00283         size(0.0)
00284 {
00285 }
00286 
00287 theme::tborder::tborder(const config& cfg) :
00288     size(lexical_cast_default<double>(cfg["border_size"], 0.0)),
00289 
00290     background_image(cfg["background_image"]),
00291     tile_image(cfg["tile_image"]),
00292 
00293     corner_image_top_left(cfg["corner_image_top_left"]),
00294     corner_image_bottom_left(cfg["corner_image_bottom_left"]),
00295 
00296     corner_image_top_right_odd(cfg["corner_image_top_right_odd"]),
00297     corner_image_top_right_even(cfg["corner_image_top_right_even"]),
00298 
00299     corner_image_bottom_right_odd(cfg["corner_image_bottom_right_odd"]),
00300     corner_image_bottom_right_even(cfg["corner_image_bottom_right_even"]),
00301 
00302     border_image_left(cfg["border_image_left"]),
00303     border_image_right(cfg["border_image_right"]),
00304 
00305     border_image_top_odd(cfg["border_image_top_odd"]),
00306     border_image_top_even(cfg["border_image_top_even"]),
00307 
00308     border_image_bottom_odd(cfg["border_image_bottom_odd"]),
00309     border_image_bottom_even(cfg["border_image_bottom_even"])
00310 {
00311     VALIDATE(size >= 0.0 && size <= 0.5, _("border_size should be between 0.0 and 0.5."));
00312 }
00313 
00314 SDL_Rect& theme::object::location(const SDL_Rect& screen) const
00315 {
00316     if(last_screen_ == screen && !location_modified_)
00317         return relative_loc_;
00318 
00319     last_screen_ = screen;
00320 
00321     switch(xanchor_) {
00322     case FIXED:
00323         relative_loc_.x = loc_.x;
00324         relative_loc_.w = loc_.w;
00325         break;
00326     case TOP_ANCHORED:
00327         relative_loc_.x = loc_.x;
00328         relative_loc_.w = screen.w - minimum<size_t>(XDim - loc_.w,screen.w);
00329         break;
00330     case BOTTOM_ANCHORED:
00331         relative_loc_.x = screen.w - minimum<size_t>(XDim - loc_.x,screen.w);
00332         relative_loc_.w = loc_.w;
00333         break;
00334     case PROPORTIONAL:
00335         relative_loc_.x = (loc_.x*screen.w)/XDim;
00336         relative_loc_.w = (loc_.w*screen.w)/XDim;
00337         break;
00338     default:
00339         assert(false);
00340     }
00341 
00342     switch(yanchor_) {
00343     case FIXED:
00344         relative_loc_.y = loc_.y;
00345         relative_loc_.h = loc_.h;
00346         break;
00347     case TOP_ANCHORED:
00348         relative_loc_.y = loc_.y;
00349         relative_loc_.h = screen.h - minimum<size_t>(YDim - loc_.h,screen.h);
00350         break;
00351     case BOTTOM_ANCHORED:
00352         relative_loc_.y = screen.h - minimum<size_t>(YDim - loc_.y,screen.h);
00353         relative_loc_.h = loc_.h;
00354         break;
00355     case PROPORTIONAL:
00356         relative_loc_.y = (loc_.y*screen.h)/YDim;
00357         relative_loc_.h = (loc_.h*screen.h)/YDim;
00358         break;
00359     default:
00360         assert(false);
00361     }
00362 
00363     relative_loc_.x = minimum<int>(relative_loc_.x,screen.w);
00364     relative_loc_.w = minimum<int>(relative_loc_.w,screen.w - relative_loc_.x);
00365     relative_loc_.y = minimum<int>(relative_loc_.y,screen.h);
00366     relative_loc_.h = minimum<int>(relative_loc_.h,screen.h - relative_loc_.y);
00367 
00368     return relative_loc_;
00369 }
00370 
00371 theme::object::ANCHORING theme::object::read_anchor(const std::string& str)
00372 {
00373     static const std::string top_anchor = "top", left_anchor = "left",
00374                              bot_anchor = "bottom", right_anchor = "right",
00375                              fixed_anchor = "fixed", proportional_anchor = "proportional";
00376     if(str == top_anchor || str == left_anchor)
00377         return TOP_ANCHORED;
00378     else if(str == bot_anchor || str == right_anchor)
00379         return BOTTOM_ANCHORED;
00380     else if(str == proportional_anchor)
00381         return PROPORTIONAL;
00382     else
00383         return FIXED;
00384 }
00385 
00386 void theme::object::modify_location(const _rect rect){
00387     loc_.x = rect.x1;
00388     loc_.y = rect.y1;
00389     loc_.w = rect.x2 - rect.x1;
00390     loc_.h = rect.y2 - rect.y1;
00391     location_modified_ = true;
00392 }
00393 
00394 void theme::object::modify_location(std::string rect_str, SDL_Rect ref_rect){
00395     _rect rect = { 0, 0, 0, 0 };
00396     const std::vector<std::string> items = utils::split(rect_str.c_str());
00397     if(items.size() >= 1) {
00398         rect.x1 = compute(items[0], ref_rect.x, ref_rect.x + ref_rect.w);
00399     }
00400     if(items.size() >= 2) {
00401         rect.y1 = compute(items[1], ref_rect.y, ref_rect.y + ref_rect.h);
00402     }
00403     if(items.size() >= 3) {
00404         rect.x2 = compute(items[2], ref_rect.x + ref_rect.w, rect.x1);
00405     }
00406     if(items.size() >= 4) {
00407         rect.y2 = compute(items[3], ref_rect.y + ref_rect.h, rect.y1);
00408     }
00409     modify_location(rect);
00410 }
00411 
00412 theme::label::label()
00413 {}
00414 
00415 theme::label::label(const config& cfg)
00416       : object(cfg), text_(cfg["prefix"].str() + cfg["text"].str() + cfg["postfix"].str()),
00417     icon_(cfg["icon"]), font_(atoi(cfg["font_size"].c_str()))
00418 {
00419     if(font_ == 0)
00420         font_ = DefaultFontSize;
00421 
00422     font_rgb_ = DefaultFontRGB;
00423     font_rgb_set_ = false;
00424     if(cfg["font_rgb"].size()){
00425     std::vector<std::string> rgb_vec = utils::split(cfg["font_rgb"]);
00426       if(3 <= rgb_vec.size()){
00427         std::vector<std::string>::iterator c=rgb_vec.begin();
00428         int r,g,b;
00429         r = (atoi(c->c_str()));
00430         c++;
00431         if(c != rgb_vec.end()){
00432           g = (atoi(c->c_str()));
00433         }else{
00434           g=0;
00435         }
00436         c++;
00437         if(c != rgb_vec.end()){
00438           b=(atoi(c->c_str()));
00439         }else{
00440           b=0;
00441         }
00442         font_rgb_ = (((r<<16) & 0x00FF0000) + ((g<<8) & 0x0000FF00) + ((b) & 0x000000FF));
00443         font_rgb_set_=true;
00444       }
00445     }
00446 }
00447 
00448 theme::status_item::status_item(const config& cfg)
00449         : object(cfg),
00450           prefix_(cfg["prefix"].str() + cfg["prefix_literal"].str()),
00451           postfix_(cfg["postfix_literal"].str() + cfg["postfix"].str()),
00452           font_(atoi(cfg["font_size"].c_str()))
00453 {
00454     if(font_ == 0)
00455         font_ = DefaultFontSize;
00456 
00457     const config* const label_child = cfg.child("label");
00458     if(label_child != NULL) {
00459         label_ = label(*label_child);
00460     }
00461 
00462     font_rgb_ = DefaultFontRGB;
00463     font_rgb_set_ = false;
00464     if(cfg["font_rgb"].size()){
00465       std::vector<std::string> rgb_vec = utils::split(cfg["font_rgb"]);
00466       if(3 <= rgb_vec.size()){
00467         std::vector<std::string>::iterator c=rgb_vec.begin();
00468         int r,g,b;
00469         r = (atoi(c->c_str()));
00470         c++;
00471         if(c != rgb_vec.end()){
00472           g = (atoi(c->c_str()));
00473         }else{
00474           g=0;
00475         }
00476         c++;
00477         if(c != rgb_vec.end()){
00478           b=(atoi(c->c_str()));
00479         }else{
00480           b=0;
00481         }
00482         font_rgb_ = (((r<<16) & 0x00FF0000) + ((g<<8) & 0x0000FF00) + ((b) & 0x000000FF));
00483         font_rgb_set_=true;
00484       }
00485     }
00486 }
00487 
00488 theme::panel::panel(const config& cfg) : object(cfg), image_(cfg["image"])
00489 {}
00490 
00491 theme::menu::menu() : context_(false)
00492 {}
00493 
00494 theme::menu::menu(const config& cfg) : object(cfg),
00495                                        context_(utils::string_bool(cfg["is_context_menu"])),
00496                                        title_(cfg["title"].str() + cfg["title_literal"].str()),
00497                                        tooltip_(cfg["tooltip"]),
00498                         image_(cfg["image"]), type_(cfg["type"]),
00499                         items_(utils::split(cfg["items"]))
00500 {}
00501 
00502 theme::theme(const config& cfg, const SDL_Rect& screen) :
00503     theme_reset_("theme_reset")
00504 {
00505     config tmp;
00506     expand_partialresolution(tmp, cfg);
00507     do_resolve_rects(tmp, cfg_);
00508     set_resolution(screen);
00509 }
00510 
00511 bool theme::set_resolution(const SDL_Rect& screen)
00512 {
00513     bool result = false;
00514 
00515     const config::child_list& resolutions = cfg_.get_children("resolution");
00516     int current_rating = 1000000;
00517     config::child_list::const_iterator i;
00518     config::child_list::const_iterator current = resolutions.end();
00519     for(i = resolutions.begin(); i != resolutions.end(); ++i) {
00520         const int width = atoi((**i)["width"].c_str());
00521         const int height = atoi((**i)["height"].c_str());
00522         LOG_DP << "comparing resolution " << screen.w << "," << screen.h << " to " << width << "," << height << "\n";
00523         if(screen.w >= width && screen.h >= height) {
00524             LOG_DP << "loading theme: " << width << "," << height << "\n";
00525             current = i;
00526             result = true;
00527             break;
00528         }
00529 
00530         const int rating = width*height;
00531         if(rating < current_rating) {
00532             current = i;
00533             current_rating = rating;
00534         }
00535     }
00536 
00537     if(current == resolutions.end()) {
00538         if(!resolutions.empty()) {
00539             LOG_STREAM(err, display) << "No valid resolution found\n";
00540         }
00541         return false;
00542     }
00543 
00544     std::map<std::string,std::string> title_stash;  
00545     std::vector<theme::menu>::iterator m;
00546     for (m = menus_.begin(); m != menus_.end(); ++m) {
00547         if (!m->title().empty() && !m->get_id().empty())
00548             title_stash[m->get_id()] = m->title();
00549     }
00550 
00551     panels_.clear();
00552     labels_.clear();
00553     status_.clear();
00554     menus_.clear();
00555 
00556     const config& cfg = **current;
00557     add_object(cfg);
00558 
00559     for (m = menus_.begin(); m != menus_.end(); ++m) {
00560         if (title_stash.find(m->get_id()) != title_stash.end())
00561             m->set_title(title_stash[m->get_id()]); 
00562     }
00563     
00564     theme_reset_.notify_observers();
00565     
00566     return result;
00567 }
00568 
00569 void theme::add_object(const config& cfg){
00570 
00571     const config* const main_map_cfg = cfg.child("main_map");
00572     if(main_map_cfg != NULL) {
00573         main_map_ = object(*main_map_cfg);
00574     }
00575 
00576     const config* const mini_map_cfg = cfg.child("mini_map");
00577     if(mini_map_cfg != NULL) {
00578         mini_map_ = object(*mini_map_cfg);
00579     }
00580 
00581     const config* const status_cfg = cfg.child("status");
00582     if(status_cfg != NULL) {
00583         for(config::child_map::const_iterator i = status_cfg->all_children().begin(); i != status_cfg->all_children().end(); ++i) {
00584             for(config::child_list::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
00585                 status_.insert(std::pair<std::string,status_item>(i->first,status_item(**j)));
00586             }
00587         }
00588         const config* const unit_image_cfg = status_cfg->child("unit_image");
00589         if (unit_image_cfg != NULL) {
00590             unit_image_ = object(*unit_image_cfg);
00591         } else {
00592             unit_image_ = object();
00593         }
00594     }
00595 
00596     const config::child_list& panel_list = cfg.get_children("panel");
00597     for(config::child_list::const_iterator p = panel_list.begin(); p != panel_list.end(); ++p) {
00598         panel new_panel(**p);
00599         set_object_location(new_panel, (**p)["rect"], (**p)["ref"]);
00600         panels_.push_back(new_panel);
00601     }
00602 
00603     const config::child_list& label_list = cfg.get_children("label");
00604     for(config::child_list::const_iterator lb = label_list.begin(); lb != label_list.end(); ++lb) {
00605         label new_label(**lb);
00606         set_object_location(new_label, (**lb)["rect"], (**lb)["ref"]);
00607         labels_.push_back(new_label);
00608     }
00609 
00610     const config::child_list& menu_list = cfg.get_children("menu");
00611     for(config::child_list::const_iterator m = menu_list.begin(); m != menu_list.end(); ++m) {
00612         menu new_menu(**m);
00613         DBG_DP << "adding menu: " << (new_menu.is_context() ? "is context" : "not context") << "\n";
00614         if(new_menu.is_context())
00615             context_ = new_menu;
00616         else{
00617             set_object_location(new_menu, (**m)["rect"], (**m)["ref"]);
00618             menus_.push_back(new_menu);
00619         }
00620 
00621         DBG_DP << "done adding menu...\n";
00622     }
00623 
00624     const config* const border_cfg = cfg.child("main_map_border");
00625     if (border_cfg != NULL) {
00626         border_ = tborder(*border_cfg);
00627     } else {
00628         border_ = tborder();
00629     }
00630 }
00631 
00632 void theme::remove_object(std::string id){
00633     for(std::vector<theme::panel>::iterator p = panels_.begin(); p != panels_.end(); ++p) {
00634         if (p->get_id() == id){
00635             panels_.erase(p);
00636             return;
00637         }
00638     }
00639     for(std::vector<theme::label>::iterator l = labels_.begin(); l != labels_.end(); ++l) {
00640         if (l->get_id() == id){
00641             labels_.erase(l);
00642             return;
00643         }
00644     }
00645     for(std::vector<theme::menu>::iterator m = menus_.begin(); m != menus_.end(); ++m) {
00646         if (m->get_id() == id){
00647             menus_.erase(m);
00648             return;
00649         }
00650     }
00651 }
00652 
00653 void theme::set_object_location(theme::object& element, std::string rect_str, std::string ref_id){
00654     theme::object ref_element = element;
00655     if (ref_id.empty()) {
00656         ref_id = element.get_id();
00657     }
00658     else {
00659         ref_element = find_element(ref_id);
00660     }
00661     if (ref_element.get_id() == ref_id){
00662         SDL_Rect ref_rect = ref_element.get_location();
00663         element.modify_location(rect_str, ref_rect);
00664     }
00665 }
00666 
00667 void theme::modify(const config* cfg){
00668     std::map<std::string,std::string> title_stash;  
00669     std::vector<theme::menu>::iterator m;
00670     for (m = menus_.begin(); m != menus_.end(); ++m) {
00671         if (!m->title().empty() && !m->get_id().empty())
00672             title_stash[m->get_id()] = m->title();
00673     }
00674 
00675     {
00676         // changes to existing theme objects
00677         const config::child_list& c = cfg->get_children("change");
00678         for(config::child_list::const_iterator j = c.begin(); j != c.end(); ++j) {
00679             std::string id = (**j)["id"];
00680             std::string ref_id = (**j)["ref"];
00681             theme::object& element = find_element(id);
00682             if (element.get_id() == id){
00683                 set_object_location(element, (**j)["rect"], ref_id);
00684             }
00685         }
00686     }
00687     // adding new theme objects
00688     {
00689         const config::child_list& c = cfg->get_children("add");
00690         for(config::child_list::const_iterator j = c.begin(); j != c.end(); ++j) {
00691             add_object(**j);
00692         }
00693     }
00694     // removing existent theme objects
00695     {
00696         const config::child_list& c = cfg->get_children("remove");
00697         for(config::child_list::const_iterator j = c.begin(); j != c.end(); ++j) {
00698             remove_object((**j)["id"]);
00699         }
00700     }
00701     for (m = menus_.begin(); m != menus_.end(); ++m) {
00702         if (title_stash.find(m->get_id()) != title_stash.end())
00703             m->set_title(title_stash[m->get_id()]); 
00704     }
00705 }
00706 
00707 theme::object& theme::find_element(std::string id){
00708     static theme::object empty_object;
00709     theme::object* res = &empty_object;
00710     for (std::vector<theme::panel>::iterator p = panels_.begin(); p != panels_.end(); ++p){
00711         if (p->get_id() == id) { res = &(*p); }
00712     }
00713     for (std::vector<theme::label>::iterator l = labels_.begin(); l != labels_.end(); ++l){
00714         if (l->get_id() == id) { res = &(*l); }
00715     }
00716     for (std::vector<theme::menu>::iterator m = menus_.begin(); m != menus_.end(); ++m){
00717         if (m->get_id() == id) { res = &(*m); }
00718     }
00719     if (id == "main-map") { res = &main_map_; }
00720     if (id == "mini-map") { res = &mini_map_; }
00721     if (id == "unit-image") { res = &unit_image_; }
00722     return *res;
00723 }
00724 
00725 const theme::status_item* theme::get_status_item(const std::string& key) const
00726 {
00727     const std::map<std::string,status_item>::const_iterator i = status_.find(key);
00728     if(i != status_.end())
00729         return &i->second;
00730     else
00731         return NULL;
00732 }
00733 
00734 std::map<std::string, config> theme::known_themes;
00735 void theme::set_known_themes(const config* cfg){
00736         known_themes.clear();
00737         if(cfg == NULL)
00738            return;
00739     const config& v = *cfg;
00740     const config::child_list& known_themes_cfg = v.get_children("theme");
00741 
00742     for(config::child_list::const_iterator thm = known_themes_cfg.begin(); thm != known_themes_cfg.end(); ++thm) {
00743            std::string thm_name=(**thm)["name"];
00744            if(thm_name!="null" && thm_name!="editor"){
00745                   known_themes[thm_name]=(**thm);
00746            }
00747     }
00748 }
00749 
00750 std::vector<std::string> theme::get_known_themes(){
00751         std::vector<std::string> names;
00752 
00753 
00754         for(std::map<std::string, config>::iterator p_thm=known_themes.begin();p_thm!=known_themes.end();p_thm++){
00755       names.push_back(p_thm->first);
00756     }
00757         return(names);
00758 }
00759 
00760 theme::menu* theme::refresh_title(const std::string& id, const std::string& new_title){
00761     theme::menu* res = NULL;
00762 
00763     for (std::vector<theme::menu>::iterator m = menus_.begin(); m != menus_.end(); ++m){
00764         if (m->get_id() == id) { 
00765             res = &(*m); 
00766             res->set_title(new_title);
00767         }
00768     }
00769 
00770     return res;
00771 }
00772 
00773 theme::menu* theme::refresh_title2(const std::string& id, const std::string& title_tag){
00774     std::string new_title = "";
00775 
00776     config& cfg = find_ref(id, cfg_, false);
00777     if (! cfg[title_tag].empty())
00778         new_title = cfg[title_tag];
00779 
00780     return refresh_title(id, new_title);
00781 }

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs