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