00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
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
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
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
00145 config& c = find_ref(id, **j, remove);
00146 if (!c["id"].empty()) {
00147 return c;
00148 }
00149 }
00150 }
00151
00152 return empty_config;
00153 }
00154
00155 #ifdef DEBUG
00156
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
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
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
00181 res_cfgs_.push_back(*parent);
00182 while(!parent_stack.empty()) {
00183
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
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
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
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
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
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
00247 if (!cfg["ref"].empty()) {
00248 if (resol_cfg == NULL) {
00249 ERR_DP << "Use of ref= outside a [resolution] block\n";
00250 } else {
00251
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
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
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
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
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 }