The Battle for Wesnoth  1.15.12+dev
unit_create.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Iris Morelle <shadowm2006@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-lib"
16 
18 
20 #include "gui/core/log.hpp"
21 #include "gui/widgets/listbox.hpp"
22 #include "gui/widgets/settings.hpp"
23 #include "gui/widgets/button.hpp"
24 #include "gui/widgets/image.hpp"
25 #include "gui/widgets/label.hpp"
26 #include "gui/widgets/grid.hpp"
28 #include "gui/widgets/text_box.hpp"
31 #include "gui/widgets/window.hpp"
32 #include "help/help.hpp"
33 #include "gettext.hpp"
34 #include "play_controller.hpp"
35 #include "units/types.hpp"
36 
37 #include <functional>
38 #include <boost/dynamic_bitset.hpp>
39 
40 static std::string last_chosen_type_id = "";
41 static std::string last_variation = "";
43 
44 namespace gui2::dialogs
45 {
46 
47 REGISTER_DIALOG(unit_create)
48 
50  : gender_(last_gender)
51  , choice_(last_chosen_type_id)
52  , variation_(last_variation)
53  , last_words_()
54 {
55  set_restore(true);
56 }
57 
59 {
60  toggle_button& male_toggle
61  = find_widget<toggle_button>(&window, "male_toggle", false);
62  toggle_button& female_toggle
63  = find_widget<toggle_button>(&window, "female_toggle", false);
64 
67 
69 
71  std::bind(&unit_create::gender_toggle_callback, this));
72 
73  menu_button& var_box = find_widget<menu_button>(&window, "variation_box", false);
74 
76 
77  listbox& list = find_widget<listbox>(&window, "unit_type_list", false);
78 
79  text_box* filter
80  = find_widget<text_box>(&window, "filter_box", false, true);
81 
83  std::bind(&unit_create::filter_text_changed, this, std::placeholders::_2));
84 
85  window.keyboard_capture(filter);
86  window.add_to_keyboard_chain(&list);
87 
89 
90  list.clear();
91 
92  for(const auto & i : unit_types.types())
93  {
94  // Make sure this unit type is built with the data we need.
96 
97  units_.push_back(&i.second);
98 
99  std::map<std::string, string_map> row_data;
100  string_map column;
101 
102  column["label"] = units_.back()->race()->plural_name();
103  row_data.emplace("race", column);
104 
105  column["label"] = units_.back()->type_name();
106  if(units_.back()->type_name().str() != units_.back()->id()) {
107  column["label"] += " (" + units_.back()->id() + ")";
108  }
109  row_data.emplace("unit_type", column);
110 
111  list.add_row(row_data);
112 
113  // Select the previous choice, if any.
114  if(!choice_.empty() && choice_ == i.first) {
115  list.select_last_row();
116  }
117  }
118 
119  if(units_.empty()) {
120  ERR_GUI_G << "no unit types found for unit create dialog; not good"
121  << std::endl;
122  }
123 
124  list.register_translatable_sorting_option(0, [this](const int i) { return (*units_[i]).race()->plural_name().str(); });
125  list.register_translatable_sorting_option(1, [this](const int i) { return (*units_[i]).type_name().str(); });
126 
127  // Select the first entry on sort if no previous selection was provided.
128  list.set_active_sorting_option({0, preferences::SORT_ORDER::ASCENDING}, choice_.empty());
129 
131 }
132 
134 {
135  listbox& list = find_widget<listbox>(&window, "unit_type_list", false);
136 
137  choice_ = "";
138 
139  if(get_retval() != retval::OK) {
140  return;
141  }
142 
143  const int selected_row = list.get_selected_row();
144  if(selected_row < 0) {
145  return;
146  } else if(static_cast<std::size_t>(selected_row) >= units_.size()) {
147  // FIXME: maybe assert?
148  ERR_GUI_G << "unit create dialog has more list items than known unit "
149  "types; not good\n";
150  return;
151  }
152 
153  last_chosen_type_id = choice_ = units_[selected_row]->id();
156 }
157 
159 {
160  window* w = get_window();
161 
162  const int selected_row
163  = find_widget<listbox>(w, "unit_type_list", false).get_selected_row();
164 
165  if(selected_row == -1) {
166  return;
167  }
168 
169  const unit_type* ut = &units_[selected_row]->get_gender_unit_type(gender_);
170 
171  if(!variation_.empty()) {
172  // This effectively translates to `ut = ut` if somehow variation_ does
173  // not refer to a variation that the unit type supports.
174  ut = &ut->get_variation(variation_);
175  }
176 
177  find_widget<unit_preview_pane>(w, "unit_details", false).set_displayed_type(*ut);
178 }
179 
181 {
182  const int selected_row
183  = find_widget<listbox>(get_window(), "unit_type_list", false).get_selected_row();
184 
185  if(selected_row == -1) {
186  return;
187  }
188 
190 
192  return units_[selected_row]->has_gender_variation(gender);
193  });
194 
195  menu_button& var_box = find_widget<menu_button>(get_window(), "variation_box", false);
196  std::vector<config> var_box_values;
197  var_box_values.emplace_back("label", _("unit_variation^Default Variation"), "variation_id", "");
198 
199  const auto& ut = *units_[selected_row];
200  const auto& uvars = ut.variation_types();
201 
202  var_box.set_active(!uvars.empty());
203 
204  unsigned n = 0, selection = 0;
205 
206  for(const auto& pair : uvars) {
207  ++n;
208 
209  const std::string& uv_id = pair.first;
210  const unit_type& uv = pair.second;
211 
212  std::string uv_label;
213  if(!uv.variation_name().empty()) {
214  uv_label = uv.variation_name() + " (" + uv_id + ")";
215  } else if(!uv.type_name().empty() && uv.type_name() != ut.type_name()) {
216  uv_label = uv.type_name() + " (" + uv_id + ")";
217  } else {
218  uv_label = uv_id;
219  }
220 
221  var_box_values.emplace_back("label", uv_label, "variation_id", uv_id);
222 
223  if(uv_id == variation_) {
224  selection = n;
225  }
226  }
227 
228  // If we didn't find the variation selection again then the new selected
229  // unit type doesn't have that variation id.
230  if(!selection) {
231  variation_.clear();
232  }
233 
234  var_box.set_values(var_box_values, selection);
235 }
236 
237 void unit_create::filter_text_changed(const std::string& text)
238 {
239  listbox& list = find_widget<listbox>(get_window(), "unit_type_list", false);
240 
241  const std::vector<std::string> words = utils::split(text, ' ');
242 
243  if(words == last_words_)
244  return;
245  last_words_ = words;
246 
247  boost::dynamic_bitset<> show_items;
248  show_items.resize(list.get_item_count(), true);
249 
250  if(!text.empty()) {
251  for(unsigned int i = 0; i < list.get_item_count(); i++) {
252  grid* row = list.get_row_grid(i);
253 
254  grid::iterator it = row->begin();
255  label& type_label
256  = find_widget<label>(*it, "unit_type", false);
257  label& race_label
258  = find_widget<label>(*it, "race", false);
259 
260  assert(i < units_.size());
261  const std::string& unit_type_id = units_[i] ? units_[i]->id() : "";
262 
263  bool found = false;
264  for(const auto & word : words)
265  {
266  found = translation::ci_search(type_label.get_label().str(), word) ||
267  translation::ci_search(race_label.get_label().str(), word) ||
268  translation::ci_search(unit_type_id, word);
269 
270  if(!found) {
271  // one word doesn't match, we don't reach words.end()
272  break;
273  }
274  }
275 
276  show_items[i] = found;
277  }
278  }
279 
280  list.set_row_shown(show_items);
281 }
282 
284 {
286 
288 }
289 
291 {
292  window& window = *this->get_window();
293  menu_button& var_box = find_widget<menu_button>(&window, "variation_box", false);
294  variation_ = var_box.get_value_config()["variation_id"].str();
295 
297 }
298 
299 } // namespace dialogs
Define the common log macros for the gui toolkit.
void set_active_sorting_option(const order_pair &sort_by, const bool select_first=false)
Sorts the listbox by a pre-set sorting option.
Definition: listbox.cpp:644
void set_text_changed_callback(std::function< void(text_box_base *textbox, const std::string text)> cb)
Set the text_changed callback.
const ::config & get_value_config() const
Returns the entire config object for the selected row.
Definition: menu_button.hpp:98
A menu_button is a styled_widget to choose an element from a list of elements.
Definition: menu_button.hpp:60
iterator begin()
Definition: grid.hpp:479
unit_race::GENDER gender()
Gender choice from the user.
Definition: unit_create.hpp:66
T get_active_member_value()
Returns the value paired with the currently actively toggled member of the group. ...
Definition: group.hpp:95
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
#define ERR_GUI_G
Definition: log.hpp:43
unit_type_data unit_types
Definition: types.cpp:1447
virtual void post_show(window &window) override
Actions to be taken after the window has been shown.
void register_translatable_sorting_option(const int col, translatable_sorter_func_t f)
Registers a special sorting function specifically for translatable values.
Definition: listbox.cpp:636
window * get_window() const
Returns a pointer to the dialog&#39;s window.
bool select_last_row(const bool select=true)
Does exactly as advertised: selects the list&#39;s last row.
Definition: listbox.hpp:194
A label displays a text, the text can be wrapped but no scrollbars are provided.
Definition: label.hpp:56
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:276
static std::string _(const char *str)
Definition: gettext.hpp:92
const unit_type_map & types() const
Definition: types.hpp:389
group< unit_race::GENDER > gender_toggle
A single unit type that the player may recruit.
Definition: types.hpp:44
Class for a single line text area.
Definition: text_box.hpp:140
void update_displayed_type() const
void build_unit_type(const unit_type &ut, unit_type::BUILD_STATUS status) const
Makes sure the provided unit_type is built to the specified level.
Definition: types.cpp:1220
unit_race::GENDER gender_
Definition: unit_create.hpp:80
The listbox class.
Definition: listbox.hpp:42
Base container class.
Definition: grid.hpp:30
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:186
This file contains the settings handling of the widget library.
const t_string & type_name() const
The name of the unit in the current language setting.
Definition: types.hpp:140
void clear()
Removes all the rows in the listbox, clearing it.
Definition: listbox.cpp:126
static std::string last_chosen_type_id
Definition: unit_create.cpp:40
static std::string last_variation
Definition: unit_create.cpp:41
Iterator for the child items.
Definition: grid.hpp:440
void filter_text_changed(const std::string &text)
void set_values(const std::vector<::config > &values, unsigned selected=0)
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:132
static unit_race::GENDER last_gender
Definition: unit_create.cpp:42
std::vector< const unit_type * > units_
Definition: unit_create.hpp:78
bool ci_search(const std::string &s1, const std::string &s2)
Definition: gettext.cpp:517
void add_member(selectable_item *w, const T &value)
Adds a widget/value pair to the group map.
Definition: group.hpp:41
std::vector< std::string > last_words_
Definition: unit_create.hpp:86
std::size_t i
Definition: function.cpp:940
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
Definition: unit_create.cpp:58
std::map< std::string, t_string > string_map
Definition: widget.hpp:26
grid & add_row(const string_map &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
Definition: listbox.cpp:67
int w
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
Definition: listbox.cpp:238
int get_retval() const
Returns the cached window exit code.
const t_string & get_label() const
bool empty() const
Definition: tstring.hpp:186
const unit_type & get_variation(const std::string &id) const
Definition: types.cpp:475
std::vector< std::string > split(const config_attribute_value &val)
void list_item_clicked()
Callbacks.
const t_string & variation_name() const
Definition: types.hpp:168
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
const std::string & str() const
Definition: tstring.hpp:190
static map_location::DIRECTION n
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:64
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
Definition: listbox.cpp:144
This shows the debug-mode dialog to create new units on the map.
Definition: unit_create.hpp:48
Class for a toggle button.
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
void set_callback_on_value_change(std::function< void(widget &)> func)
Sets a common callback function for all members.
Definition: group.hpp:120