From 877ac69366ae2cfabc6ff089ff4c723b2362e183 Mon Sep 17 00:00:00 2001 From: Subhraman Sarkar Date: Mon, 17 Mar 2025 16:58:52 +0530 Subject: [PATCH] rich label: support setting table bgcolors from definition --- .../default/widgets/rich_label_default.cfg | 6 ++ data/schema/gui/widget_definitions.cfg | 6 ++ src/gui/widgets/rich_label.cpp | 95 +++++++++++++------ src/gui/widgets/rich_label.hpp | 23 ++--- src/help/help_topic_generators.cpp | 15 ++- 5 files changed, 101 insertions(+), 44 deletions(-) diff --git a/data/gui/themes/default/widgets/rich_label_default.cfg b/data/gui/themes/default/widgets/rich_label_default.cfg index 9be30d6ad04..bf3c34e1fd6 100644 --- a/data/gui/themes/default/widgets/rich_label_default.cfg +++ b/data/gui/themes/default/widgets/rich_label_default.cfg @@ -28,6 +28,12 @@ link_color = "255, 225, 0" + [colors] + table_header = "51, 55, 79, 255" + table_row1 = "26, 31, 51, 255" + table_row2 = "35, 40, 66, 255" + [/colors] + [state_enabled] [draw][/draw] diff --git a/data/schema/gui/widget_definitions.cfg b/data/schema/gui/widget_definitions.cfg index 5e2a921f03a..6de91682e1b 100644 --- a/data/schema/gui/widget_definitions.cfg +++ b/data/schema/gui/widget_definitions.cfg @@ -227,6 +227,12 @@ min="0" max="infinite" super="$generic/widget_definition/resolution" + [tag] + name="colors" + min=0 + max=1 + {SIMPLE_KEY * color} + [/tag] [tag] name="state_disabled" min="0" diff --git a/src/gui/widgets/rich_label.cpp b/src/gui/widgets/rich_label.cpp index f643489a1ad..b3def53326e 100644 --- a/src/gui/widgets/rich_label.cpp +++ b/src/gui/widgets/rich_label.cpp @@ -67,6 +67,7 @@ rich_label::rich_label(const implementation::builder_rich_label& builder) , can_wrap_(true) , link_aware_(builder.link_aware) , link_color_(font::YELLOW_COLOR) + , predef_colors_() , font_size_(font::SIZE_NORMAL) , can_shrink_(true) , text_alpha_(ALPHA_OPAQUE) @@ -75,9 +76,27 @@ rich_label::rich_label(const implementation::builder_rich_label& builder) , size_(0, 0) , padding_(builder.padding) { + const auto conf = cast_config_to(); + assert(conf); + text_color_enabled_ = conf->text_color_enabled; + text_color_disabled_ = conf->text_color_disabled; + font_family_ = conf->font_family; + font_size_ = conf->font_size; + font_style_ = conf->font_style; + link_color_ = conf->link_color; + predef_colors_.insert(conf->colors.begin(), conf->colors.end()); + set_text_alignment(builder.text_alignment); + set_label(get_label()); } -wfl::map_formula_callable rich_label::setup_text_renderer(config text_cfg, unsigned width) const { +color_t rich_label::get_color(const std::string& color) +{ + const auto iter = predef_colors_.find(color); + return (iter != predef_colors_.end()) ? iter->second : font::string_to_color(color); +} + +wfl::map_formula_callable rich_label::setup_text_renderer(config text_cfg, unsigned width) const +{ // Set up fake render to calculate text position static wfl::action_function_symbol_table functions; wfl::map_formula_callable variables; @@ -89,7 +108,8 @@ wfl::map_formula_callable rich_label::setup_text_renderer(config text_cfg, unsig return variables; } -point rich_label::get_text_size(config& text_cfg, unsigned width) const { +point rich_label::get_text_size(config& text_cfg, unsigned width) const +{ wfl::map_formula_callable variables = setup_text_renderer(text_cfg, width); return { variables.query_value("text_width").as_int(), @@ -97,7 +117,8 @@ point rich_label::get_text_size(config& text_cfg, unsigned width) const { }; } -point rich_label::get_image_size(config& img_cfg) const { +point rich_label::get_image_size(config& img_cfg) const +{ static wfl::action_function_symbol_table functions; wfl::map_formula_callable variables; variables.add("fake_draw", wfl::variant(true)); @@ -108,7 +129,8 @@ point rich_label::get_image_size(config& img_cfg) const { }; } -std::pair rich_label::add_text(config& curr_item, const std::string& text) { +std::pair rich_label::add_text(config& curr_item, const std::string& text) +{ auto& attr = curr_item["text"]; size_t start = attr.str().size(); attr = attr.str() + text; @@ -116,7 +138,13 @@ std::pair rich_label::add_text(config& curr_item, const std::str return { start, end }; } -void rich_label::add_attribute(config& curr_item, const std::string& attr_name, size_t start, size_t end, const std::string& extra_data) { +void rich_label::add_attribute( + config& curr_item, + const std::string& attr_name, + size_t start, + size_t end, + const std::string& extra_data) +{ curr_item.add_child("attribute", config{ "name" , attr_name, "start" , start, @@ -125,13 +153,24 @@ void rich_label::add_attribute(config& curr_item, const std::string& attr_name, }); } -std::pair rich_label::add_text_with_attribute(config& curr_item, const std::string& text, const std::string& attr_name, const std::string& extra_data) { +std::pair rich_label::add_text_with_attribute( + config& curr_item, + const std::string& text, + const std::string& attr_name, + const std::string& extra_data) +{ const auto [start, end] = add_text(curr_item, text); add_attribute(curr_item, attr_name, start, end, extra_data); return { start, end }; } -void rich_label::add_link(config& curr_item, const std::string& name, const std::string& dest, const point& origin, int img_width) { +void rich_label::add_link( + config& curr_item, + const std::string& name, + const std::string& dest, + const point& origin, + int img_width) +{ // TODO algorithm needs to be text_alignment independent DBG_GUI_RL << "add_link: " << name << "->" << dest; @@ -177,8 +216,8 @@ void rich_label::add_link(config& curr_item, const std::string& name, const std: } } -size_t rich_label::get_split_location(std::string_view text, const point& pos) { - +size_t rich_label::get_split_location(std::string_view text, const point& pos) +{ size_t len = get_offset_from_xy(pos); len = (len > text.size()-1) ? text.size()-1 : len; @@ -194,7 +233,11 @@ size_t rich_label::get_split_location(std::string_view text, const point& pos) { return len; } -std::vector rich_label::split_in_width(const std::string &s, const int font_size, const unsigned width) { +std::vector rich_label::split_in_width( + const std::string &s, + const int font_size, + const unsigned width) +{ std::vector res; try { const std::string& first_line = font::pango_word_wrap(s, font_size, width, -1, 1, true); @@ -445,7 +488,7 @@ std::pair rich_label::get_parsed_text( bgbox["y"] = pos.y; bgbox["w"] = std::accumulate(col_widths.begin(), col_widths.end(), 0) + 2*(row_paddings[0] + row_paddings[1])*columns; bgbox["h"] = row_paddings[0] + row_heights[row_idx] + row_paddings[1]; - bgbox["fill_color"] = font::string_to_color(row["bgcolor"]).to_rgba_string(); + bgbox["fill_color"] = get_color(row["bgcolor"].str()).to_rgba_string(); text_dom.append(std::move(bg_base)); } @@ -793,7 +836,12 @@ std::pair rich_label::get_parsed_text( return { text_dom, point(w, h - origin.y) }; } // function ends -void rich_label::default_text_config(config* txt_ptr, const point& pos, const int max_width, const t_string& text) { +void rich_label::default_text_config( + config* txt_ptr, + const point& pos, + const int max_width, + const t_string& text) +{ if (txt_ptr != nullptr) { (*txt_ptr)["text"] = text; (*txt_ptr)["color"] = text_color_enabled_.to_rgba_string(); @@ -977,7 +1025,14 @@ rich_label_definition::resolution::resolution(const config& cfg) , font_family(cfg["text_font_family"].str()) , font_size(cfg["text_font_size"].to_int(font::SIZE_NORMAL)) , font_style(cfg["text_font_style"].str("normal")) + , colors() { + if(auto colors_cfg = cfg.optional_child("colors")) { + for (const auto& [name, value] : colors_cfg->attribute_range()) { + colors.try_emplace(name, color_t::from_rgba_string(value.str())); + } + } + // Note the order should be the same as the enum state_t is rich_label.hpp. state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_enabled", missing_mandatory_wml_tag("rich_label_definition][resolution", "state_enabled"))); state.emplace_back(VALIDATE_WML_CHILD(cfg, "state_disabled", missing_mandatory_wml_tag("rich_label_definition][resolution", "state_disabled"))); @@ -999,24 +1054,10 @@ builder_rich_label::builder_rich_label(const config& cfg) std::unique_ptr builder_rich_label::build() const { - auto lbl = std::make_unique(*this); - - const auto conf = lbl->cast_config_to(); - assert(conf); - - lbl->set_text_alignment(text_alignment); - lbl->set_text_color(conf->text_color_enabled, true); - lbl->set_text_color(conf->text_color_disabled, false); - lbl->set_link_color(conf->link_color); - lbl->set_font_family(conf->font_family); - lbl->set_font_size(conf->font_size); - lbl->set_font_style(conf->font_style); - lbl->set_label(lbl->get_label()); - DBG_GUI_G << "Window builder: placed rich_label '" << id << "' with definition '" << definition << "'."; - return lbl; + return std::make_unique(*this); } } // namespace implementation diff --git a/src/gui/widgets/rich_label.hpp b/src/gui/widgets/rich_label.hpp index 09fa4027d88..b8d2f83ee0b 100644 --- a/src/gui/widgets/rich_label.hpp +++ b/src/gui/widgets/rich_label.hpp @@ -93,11 +93,6 @@ public: can_wrap_ = wrap; } - void set_characters_per_line(const unsigned characters_per_line) - { - characters_per_line_ = characters_per_line; - } - void set_link_aware(bool l); void set_link_color(const color_t& color); @@ -124,15 +119,6 @@ public: void set_text_alpha(unsigned short alpha); - void set_text_color(const color_t& color, bool enabled) - { - if (enabled) { - text_color_enabled_ = color; - } else { - text_color_disabled_ = color; - } - } - const t_string& get_label() const { return unparsed_text_.empty() ? styled_widget::get_label() : unparsed_text_; @@ -207,6 +193,11 @@ private: */ color_t link_color_; + /** + * Color variables that can be used in place of colors strings, like `` + */ + std::map predef_colors_; + /** * Base font family */ @@ -245,6 +236,9 @@ private: /** Padding */ int padding_; + /** If color is a predefined color set in resolution, return it, otherwise decode using `font::string_to_color`. */ + color_t get_color(const std::string& color); + /** Create template for text config that can be shown in canvas */ void default_text_config(config* txt_ptr, const point& pos, const int max_width, const t_string& text = ""); @@ -341,6 +335,7 @@ struct rich_label_definition : public styled_widget_definition std::string font_family; int font_size; std::string font_style; + std::map colors; }; }; diff --git a/src/help/help_topic_generators.cpp b/src/help/help_topic_generators.cpp index 67b12ed5d20..b2ec7f76c64 100644 --- a/src/help/help_topic_generators.cpp +++ b/src/help/help_topic_generators.cpp @@ -676,6 +676,7 @@ std::string unit_topic_generator::operator()() const { // Print headers for the table. table_ss << markup::tag("row", + { {"bgcolor", "table_header"} }, //FIXME space/tab does not work, but nbsp does //empty tags will be skipped by rich_label markup::tag("col", font::nbsp), @@ -742,7 +743,7 @@ std::string unit_topic_generator::operator()() const { } } - table_ss << markup::tag("row", {{"valign", "center"}}, attack_ss.str()); + table_ss << markup::tag("row", { {"valign", "center"} }, attack_ss.str()); } ss << markup::tag("table", table_ss.str()); @@ -777,10 +778,12 @@ std::string unit_topic_generator::operator()() const { std::stringstream().swap(table_ss); table_ss << markup::tag("row", + { {"bgcolor", "table_header"} }, markup::tag("col", markup::bold(_("Attack Type"))), markup::tag("col", markup::bold(_("Resistance")))); utils::string_map_res dam_tab = movement_type.damage_table(); + bool odd_row = true; for(std::pair dam_it : dam_tab) { int resistance = 100; try { @@ -795,8 +798,11 @@ std::string unit_topic_generator::operator()() const { const std::string lang_type = string_table["type_" + dam_it.first]; const std::string type_icon = "icons/profiles/" + dam_it.first + ".png~SCALE_INTO(16,16)"; table_ss << markup::tag("row", + { {"bgcolor", (odd_row ? "table_row1" : "table_row2")} }, markup::tag("col", markup::img(type_icon), lang_type), markup::tag("col", markup::span_color(color, resist))); + + odd_row = !odd_row; } ss << markup::tag("table", table_ss.str()); @@ -816,7 +822,7 @@ std::string unit_topic_generator::operator()() const { if (has_terrain_defense_caps) { row_ss << markup::tag("col", markup::bold(_("Defense Cap"))); } if (has_vision) { row_ss << markup::tag("col", markup::bold(_("Vision Cost"))); } if (has_jamming) { row_ss << markup::tag("col", markup::bold(_("Jamming Cost"))); } - table_ss << markup::tag("row", row_ss.str()); + table_ss << markup::tag("row", { {"bgcolor", "table_header"} }, row_ss.str()); // Organize terrain movetype data std::set terrain_moves; @@ -848,6 +854,7 @@ std::string unit_topic_generator::operator()() const { } // Add movement table rows + odd_row = true; for(const terrain_movement_info& m : terrain_moves) { std::stringstream().swap(row_ss); @@ -887,7 +894,9 @@ std::string unit_topic_generator::operator()() const { row_ss << markup::tag("col", format_mp_entry(type_.jamming(), m.jamming_cost)); } - table_ss << markup::tag("row", row_ss.str()); + table_ss << markup::tag("row", { {"bgcolor", (odd_row ? "table_row1" : "table_row2")} }, row_ss.str()); + + odd_row = !odd_row; } ss << markup::tag("table", table_ss.str());