theme.cpp

Go to the documentation of this file.
00001 /* $Id: theme.cpp 53881 2012-04-09 15:34:47Z fendrin $ */
00002 /*
00003    Copyright (C) 2003 - 2012 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 as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY.
00012 
00013    See the COPYING file for more details.
00014 */
00015 
00016 /** @file */
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     // If x2 or y2 are not specified, use x1 and y1 values
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         // DBG_DP << "Rect " << rect_str << "\t: " << resolved.str() << "\n";
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         // Recursively look in children.
00136         config &c = find_ref(id, icfg, remove);
00137         if (&c != &empty_config) {
00138             return c;
00139         }
00140     }
00141 
00142     // Not found.
00143     return empty_config;
00144 }
00145 
00146 #ifdef DEBUG
00147 
00148 // to be called from gdb
00149 static config& find_ref(const char* id, config& cfg) {
00150     return find_ref(std::string(id),cfg);
00151 }
00152 
00153 namespace {
00154     // avoid some compiler warnings in stricter mode.
00155     static config cfg;
00156     static config& result = find_ref("", cfg);
00157 } // namespace
00158 
00159 #endif
00160 
00161 static void expand_partialresolution(config& dst_cfg, const config& top_cfg)
00162 {
00163     std::vector<config> res_cfgs_;
00164     // resolve all the partialresolutions
00165     foreach (const config &part, top_cfg.child_range("partialresolution"))
00166     {
00167         // follow the inheritance hierarchy and push all the nodes on the stack
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         // 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             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             // cannot add [status] sub-elements, but who cares
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     // Add all the resolutions
00207     foreach (const config &res, top_cfg.child_range("resolution")) {
00208         dst_cfg.add_child("resolution", res);
00209     }
00210     // Add all the resolved resolutions
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         // recursively resolve children
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         // copy all key/values
00227         resolved_config.merge_attributes(cfg);
00228 
00229         // override default reference rect with "ref" parameter if any
00230         if (!cfg["ref"].empty()) {
00231             if (resol_cfg == NULL) {
00232                 ERR_DP << "Use of ref= outside a [resolution] block\n";
00233             } else {
00234                 //DBG_DP << ">> Looking for " << cfg["ref"] << "\n";
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         // resolve the rect value to absolute coordinates
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     // Change existing theme objects.
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     // Add new theme objects.
00722     foreach (const config &c, cfg.child_range("add")) {
00723         add_object(c);
00724     }
00725 
00726     // Remove existent theme objects.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Fri May 25 2012 01:03:12 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs