The Battle for Wesnoth  1.15.0+dev
faction_select.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2018 by the Battle for Wesnoth Project https://www.wesnoth.org/
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY.
10 
11  See the COPYING file for more details.
12 */
13 
14 #define GETTEXT_DOMAIN "wesnoth-lib"
15 
17 
18 #include "game_config_manager.hpp"
21 #include "gui/core/log.hpp"
22 #include "gui/widgets/listbox.hpp"
23 #include "gui/widgets/settings.hpp"
24 #include "gui/widgets/image.hpp"
25 #include "gui/widgets/label.hpp"
26 #include "gui/widgets/button.hpp"
29 #include "gui/widgets/window.hpp"
30 #include "formatter.hpp"
31 #include "gettext.hpp"
32 #include "help/help.hpp"
33 #include "preferences/game.hpp" // for encountered_units
34 #include "units/types.hpp"
35 
36 #include "utils/functional.hpp"
37 
38 namespace gui2
39 {
40 namespace dialogs
41 {
42 
43 REGISTER_DIALOG(faction_select)
44 
45 faction_select::faction_select(ng::flg_manager& flg_manager, const std::string& color, const int side)
46  : flg_manager_(flg_manager)
47  , tc_color_(color)
48  , side_(side)
49  , last_faction_(flg_manager.current_faction_index())
50  , last_leader_(flg_manager.current_leader_index())
51  , last_gender_(flg_manager.current_gender_index())
52 {
53 }
54 
56 {
57  find_widget<label>(&window, "starting_pos", false).set_label(std::to_string(side_));
58 
59  //
60  // Set up gender radio buttons
61  //
62  toggle_button& gender_rand = find_widget<toggle_button>(&window, "gender_random", false);
63  toggle_button& gender_male = find_widget<toggle_button>(&window, "gender_male", false);
64  toggle_button& gender_female = find_widget<toggle_button>(&window, "gender_female", false);
65 
66  gender_toggle_.add_member(&gender_rand, "random");
69 
71 
73  std::bind(&faction_select::on_gender_select, this, std::ref(window)));
74 
75  //
76  // Set up leader menu button
77  //
78  connect_signal_notify_modified(find_widget<menu_button>(&window, "leader_menu", false),
79  std::bind(&faction_select::on_leader_select, this, std::ref(window)));
80 
81  // Leader's profile button
82  find_widget<button>(&window, "type_profile", false).connect_click_handler(
83  std::bind(&faction_select::profile_button_callback, this, std::ref(window)));
84 
85  //
86  // Set up faction list
87  //
88  listbox& list = find_widget<listbox>(&window, "faction_list", false);
89 
90  window.keyboard_capture(&list);
91 
93  std::bind(&faction_select::on_faction_select, this, std::ref(window)));
94 
95  for(const config *s : flg_manager_.choosable_factions()) {
96  const config& side = *s;
97 
98  std::map<std::string, string_map> data;
100 
101  const std::string name = side["name"].str();
102  // flag_rgb here is unrelated to any handling in the unit class
103  const std::string flag_rgb = !side["flag_rgb"].empty() ? side["flag_rgb"].str() : "magenta";
104 
105  // Handle legacy DescriptionWML format.
106  if(name.find_first_of("=") != std::string::npos) {
107  gui2::legacy_menu_item parsed(name, "Use separate name= and image= keys. Multiple text columns are no longer supported.");
108 
109  if(!side.has_attribute("image")) {
110  item["label"] = (formatter() << parsed.icon() << "~RC(" << flag_rgb << ">" << tc_color_ << ")").str();
111  data.emplace("faction_image", item);
112  }
113 
114  item["label"] = parsed.label();
115  if(!parsed.description().empty()) {
116  item["label"] += " " + parsed.description();
117  }
118  data.emplace("faction_name", item);
119  } else {
120  item["label"] = (formatter() << side["image"] << "~RC(" << flag_rgb << ">" << tc_color_ << ")").str();
121  data.emplace("faction_image", item);
122 
123  item["label"] = name;
124  data.emplace("faction_name", item);
125  }
126 
127  list.add_row(data);
128  }
129 
130  list.select_row(flg_manager_.current_faction_index());
131 
132  on_faction_select(window);
133 }
134 
136 {
137  const int selected_row = find_widget<listbox>(&window, "faction_list", false).get_selected_row();
138 
139  if(selected_row == -1) {
140  return;
141  }
142 
143  // Since set_current_faction overrides the current leader, save a copy of the previous leader index so the
144  // leader dropdown can be set to the appropriate initial selection.
145  const int previous_leader_selection = flg_manager_.current_leader_index();
146 
147  flg_manager_.set_current_faction(selected_row);
148 
149  std::vector<config> leaders;
150 
151  for(const std::string& leader : flg_manager_.choosable_leaders()) {
152  const unit_type* unit = unit_types.find(leader);
153 
154  if(unit) {
155  const std::string icon = formatter() << unit->image() << "~RC(" << unit->flag_rgb() << ">" << tc_color_ << ")";
156  leaders.emplace_back("label", unit->type_name(), "icon", icon);
157  } else if(leader == "random") {
158  leaders.emplace_back("label", _("Random"), "icon", ng::random_enemy_picture);
159  } else if(leader == "null") {
160  leaders.emplace_back("label", font::unicode_em_dash);
161  } else {
162  leaders.emplace_back("label", "?");
163  }
164  }
165 
166  menu_button& leader_dropdown = find_widget<menu_button>(&window, "leader_menu", false);
167 
168  leader_dropdown.set_values(leaders, std::min<int>(leaders.size() - 1, previous_leader_selection));
169  leader_dropdown.set_active(leaders.size() > 1 && !flg_manager_.is_saved_game());
170 
171  on_leader_select(window);
172 
173  // Print recruits
174  const std::vector<std::string> recruit_list = utils::split(flg_manager_.current_faction()["recruit"]);
175  std::vector<t_string> recruit_names;
176 
177  for(const auto& recruit : recruit_list) {
178  if(const unit_type* rt = unit_types.find(recruit)) {
179  recruit_names.push_back(font::unicode_bullet + " " + rt->type_name());
180  }
181  }
182 
183  std::sort(recruit_names.begin(), recruit_names.end(), [](const std::string& s1, const std::string& s2) {
184  return translation::compare(s1, s2) < 0;
185  });
186 
187  find_widget<styled_widget>(&window, "recruits", false).set_label(utils::join(recruit_names, "\n"));
188 }
189 
191 {
192  flg_manager_.set_current_leader(find_widget<menu_button>(&window, "leader_menu", false).get_value());
193 
194  // TODO: should we decouple this from the flg manager and instead just check the unit type directly?
195  // If that's done so, we'd need to come up with a different check for Random availability.
196  gender_toggle_.set_members_enabled([this](const std::string& gender)->bool {
197  const std::vector<std::string>& genders = flg_manager_.choosable_genders();
198  return std::find(genders.begin(), genders.end(), gender) != genders.end();
199  });
200 
201  update_leader_image(window);
202 
203  // Disable the profile button if leader_type is dash or "Random"
204  button& profile_button = find_widget<button>(&window, "type_profile", false);
205  const std::string& leader_type = find_widget<menu_button>(&window, "leader_menu", false).get_value_string();
206  profile_button.set_active(unit_types.find(leader_type) != nullptr);
207 }
208 
210 {
211  const std::string& leader_type = find_widget<menu_button>(&window, "leader_menu", false).get_value_string();
212  const unit_type* ut = unit_types.find(leader_type);
213  if(ut != nullptr) {
214  preferences::encountered_units().insert(ut->id());
217  }
218 }
219 
221 {
223 
224  update_leader_image(window);
225 }
226 
228 {
229  std::string leader_image = ng::random_enemy_picture;
230 
233  leader_image = formatter() << utg.image() << "~RC(" << utg.flag_rgb() << ">" << tc_color_ << ")" << "~SCALE_INTO_SHARP(144,144)";
234  }
235 
236  find_widget<image>(&window, "leader_image", false).set_label(leader_image);
237 }
238 
240 {
241  //
242  // If we're canceling, restore the previous selections. It might be worth looking
243  // into only making selections at all here in post_show, but that would require a
244  // refactor of the flg_manager class.
245  //
246  // Also, note it's important to set these in the order of faction -> leader -> gender
247  // or the saved indices will be invalid!
248  //
249  // -- vultraz, 2018-06-16
250  //
251  if(get_retval() != retval::OK) {
255  }
256 }
257 
258 } // namespace dialogs
259 } // namespace gui2
Define the common log macros for the gui toolkit.
const std::vector< std::string > & choosable_genders() const
Definition: flg_manager.hpp:64
int current_faction_index() const
static const std::string s_male
Standard string id (not translatable) for MALE.
Definition: race.hpp:28
virtual void post_show(window &window) override
Inherited from modal_dialog.
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
Definition: types.cpp:1267
This class represents a single unit of a specific type.
Definition: unit.hpp:99
Simple push button.
Definition: menu_button.hpp:41
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
const std::string & current_gender() const
Definition: flg_manager.hpp:70
const std::string & icon() const
Definition: old_markup.hpp:44
bool has_attribute(config_key_type key) const
Definition: config.cpp:213
T get_active_member_value()
Returns the value paired with the currently actively toggled member of the group. ...
Definition: group.hpp:95
int compare(const std::string &s1, const std::string &s2)
Case-sensitive lexicographical comparison.
Definition: gettext.cpp:458
const std::string & flag_rgb() const
Definition: types.cpp:744
This file contains the window object, this object is a top level container which has the event manage...
void set_members_enabled(std::function< bool(const T &)> predicate)
Wrapper for enabling or disabling member widgets.
Definition: group.hpp:142
unit_type_data unit_types
Definition: types.cpp:1525
void set_current_leader(const unsigned index)
STL namespace.
int current_leader_index() const
Definition: flg_manager.hpp:78
void set_current_gender(const unsigned index)
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
A single unit type that the player may recruit.
Definition: types.hpp:42
Generic file dialog.
Definition: field-fwd.hpp:22
const std::vector< const config * > & choosable_factions() const
Definition: flg_manager.hpp:60
static const std::string s_female
Standard string id (not translatable) for FEMALE.
Definition: race.hpp:27
The listbox class.
Definition: listbox.hpp:40
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
static game_config_manager * get()
const std::vector< std::string > & choosable_leaders() const
Definition: flg_manager.hpp:62
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification_function &signal)
Connects a signal handler for getting a notification upon modification.
Definition: dispatcher.cpp:248
This file contains the settings handling of the widget library.
std::ostringstream wrapper.
Definition: formatter.hpp:38
const t_string & type_name() const
The name of the unit in the current language setting.
Definition: types.hpp:135
const std::string & current_leader() const
Definition: flg_manager.hpp:68
void set_values(const std::vector<::config > &values, unsigned selected=0)
const std::string & id() const
The id for this unit_type.
Definition: types.hpp:138
bool is_saved_game() const
Definition: flg_manager.hpp:51
void show_unit_description(const unit &u)
Definition: help.cpp:58
void profile_button_callback(window &window)
Various uncategorised dialogs.
std::string flag_rgb
void set_current_faction(const unsigned index)
void add_member(selectable_item *w, const T &value)
Adds a widget/value pair to the group map.
Definition: group.hpp:41
const config & current_faction() const
Definition: flg_manager.hpp:66
Game configuration data as global variables.
Definition: build_info.cpp:49
static map_location::DIRECTION s
const std::string & label() const
Definition: old_markup.hpp:49
void on_faction_select(window &window)
Callbacks.
std::map< std::string, t_string > string_map
Definition: widget.hpp:24
std::set< std::string > & encountered_units()
Definition: game.cpp:954
void update_leader_image(window &window)
const std::string unicode_bullet
Definition: constants.cpp:43
static int sort(lua_State *L)
Definition: ltablib.cpp:411
const std::string random_enemy_picture("units/random-dice.png")
const std::string & image() const
Definition: types.hpp:161
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: button.cpp:62
void on_gender_select(window &window)
bool find(E event, F functor)
Tests whether an event handler is available.
void on_leader_select(window &window)
const std::string unicode_em_dash
Definition: constants.cpp:40
Simple push button.
Definition: button.hpp:35
group< std::string > gender_toggle_
const unit_type & get_gender_unit_type(std::string gender) const
Returns a gendered variant of this unit_type.
Definition: types.cpp:445
Implements simple parsing of legacy GUI1 item markup.
Definition: old_markup.hpp:25
virtual void set_active(const bool active) override
See styled_widget::set_active.
Definition: menu_button.cpp:74
Dialog was closed with the OK button.
Definition: retval.hpp:34
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
virtual void pre_show(window &window) override
Inherited from modal_dialog.
base class of top level items, the only item which needs to store the final canvases to draw on ...
Definition: window.hpp:63
bool empty() const
Definition: config.cpp:884
Class for a toggle button.
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:371
void set_member_states(const T &value)
Sets the toggle values for all widgets besides the one associated with the specified value to false...
Definition: group.hpp:110
const std::string & description() const
Definition: old_markup.hpp:54
void set_callback_on_value_change(std::function< void(widget &)> func)
Sets a common callback function for all members.
Definition: group.hpp:120