The Battle for Wesnoth  1.15.7+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 "utils/functional.hpp"
38 #include <boost/dynamic_bitset.hpp>
39 
43 
44 namespace gui2
45 {
46 namespace dialogs
47 {
48 
49 /*WIKI
50  * @page = GUIWindowDefinitionWML
51  * @order = 2_unit_create
52  *
53  * == Unit create ==
54  *
55  * This shows the debug-mode dialog to create new units on the map.
56  *
57  * @begin{table}{dialog_widgets}
58  *
59  * male_toggle & & toggle_button & m &
60  * Option button to select the "male" gender for created units. $
61  *
62  * female_toggle & & toggle_button & m &
63  * Option button to select the "female" gender for created units. $
64  *
65  * unit_type_list & & listbox & m &
66  * Listbox displaying existing unit types sorted by name and race. $
67  *
68  * -unit_type & & styled_widget & m &
69  * Widget which shows the unit type name label. $
70  *
71  * -race & & styled_widget & m &
72  * Widget which shows the unit race name label. $
73  *
74  * @end{table}
75  */
76 
77 REGISTER_DIALOG(unit_create)
78 
80  : gender_(last_gender)
81  , choice_(last_chosen_type_id)
82  , variation_(last_variation)
83  , last_words_()
84 {
85  set_restore(true);
86 }
87 
89 {
90  toggle_button& male_toggle
91  = find_widget<toggle_button>(&window, "male_toggle", false);
92  toggle_button& female_toggle
93  = find_widget<toggle_button>(&window, "female_toggle", false);
94 
97 
99 
101  std::bind(&unit_create::gender_toggle_callback, this));
102 
103  menu_button& var_box = find_widget<menu_button>(&window, "variation_box", false);
104 
106 
107  listbox& list = find_widget<listbox>(&window, "unit_type_list", false);
108 
109  text_box* filter
110  = find_widget<text_box>(&window, "filter_box", false, true);
111 
113  std::bind(&unit_create::filter_text_changed, this, _2));
114 
115  window.keyboard_capture(filter);
116  window.add_to_keyboard_chain(&list);
117 
119 
120  list.clear();
121 
122  for(const auto & i : unit_types.types())
123  {
124  // Make sure this unit type is built with the data we need.
126 
127  units_.push_back(&i.second);
128 
129  std::map<std::string, string_map> row_data;
130  string_map column;
131 
132  column["label"] = units_.back()->race()->plural_name();
133  row_data.emplace("race", column);
134 
135  column["label"] = units_.back()->type_name();
136  if(units_.back()->type_name().str() != units_.back()->id()) {
137  column["label"] += " (" + units_.back()->id() + ")";
138  }
139  row_data.emplace("unit_type", column);
140 
141  list.add_row(row_data);
142 
143  // Select the previous choice, if any.
144  if(!choice_.empty() && choice_ == i.first) {
145  list.select_last_row();
146  }
147  }
148 
149  if(units_.empty()) {
150  ERR_GUI_G << "no unit types found for unit create dialog; not good"
151  << std::endl;
152  }
153 
154  list.register_translatable_sorting_option(0, [this](const int i) { return (*units_[i]).race()->plural_name().str(); });
155  list.register_translatable_sorting_option(1, [this](const int i) { return (*units_[i]).type_name().str(); });
156 
157  // Select the first entry on sort if no previous selection was provided.
158  list.set_active_sorting_option({0, preferences::SORT_ORDER::ASCENDING}, choice_.empty());
159 
161 }
162 
164 {
165  listbox& list = find_widget<listbox>(&window, "unit_type_list", false);
166 
167  choice_ = "";
168 
169  if(get_retval() != retval::OK) {
170  return;
171  }
172 
173  const int selected_row = list.get_selected_row();
174  if(selected_row < 0) {
175  return;
176  } else if(static_cast<std::size_t>(selected_row) >= units_.size()) {
177  // FIXME: maybe assert?
178  ERR_GUI_G << "unit create dialog has more list items than known unit "
179  "types; not good\n";
180  return;
181  }
182 
183  last_chosen_type_id = choice_ = units_[selected_row]->id();
186 }
187 
189 {
190  window* w = get_window();
191 
192  const int selected_row
193  = find_widget<listbox>(w, "unit_type_list", false).get_selected_row();
194 
195  if(selected_row == -1) {
196  return;
197  }
198 
199  const unit_type* ut = &units_[selected_row]->get_gender_unit_type(gender_);
200 
201  if(!variation_.empty()) {
202  // This effectively translates to `ut = ut` if somehow variation_ does
203  // not refer to a variation that the unit type supports.
204  ut = &ut->get_variation(variation_);
205  }
206 
207  find_widget<unit_preview_pane>(w, "unit_details", false).set_displayed_type(*ut);
208 }
209 
211 {
212  const int selected_row
213  = find_widget<listbox>(get_window(), "unit_type_list", false).get_selected_row();
214 
215  if(selected_row == -1) {
216  return;
217  }
218 
220 
222  return units_[selected_row]->has_gender_variation(gender);
223  });
224 
225  menu_button& var_box = find_widget<menu_button>(get_window(), "variation_box", false);
226  std::vector<config> var_box_values;
227  var_box_values.emplace_back("label", _("unit_variation^Default Variation"), "variation_id", "");
228 
229  const auto& ut = *units_[selected_row];
230  const auto& uvars = ut.variation_types();
231 
232  var_box.set_active(!uvars.empty());
233 
234  unsigned n = 0, selection = 0;
235 
236  for(const auto& pair : uvars) {
237  ++n;
238 
239  const std::string& uv_id = pair.first;
240  const unit_type& uv = pair.second;
241 
242  std::string uv_label;
243  if(!uv.variation_name().empty()) {
244  uv_label = uv.variation_name() + " (" + uv_id + ")";
245  } else if(!uv.type_name().empty() && uv.type_name() != ut.type_name()) {
246  uv_label = uv.type_name() + " (" + uv_id + ")";
247  } else {
248  uv_label = uv_id;
249  }
250 
251  var_box_values.emplace_back("label", uv_label, "variation_id", uv_id);
252 
253  if(uv_id == variation_) {
254  selection = n;
255  }
256  }
257 
258  // If we didn't find the variation selection again then the new selected
259  // unit type doesn't have that variation id.
260  if(!selection) {
261  variation_.clear();
262  }
263 
264  var_box.set_values(var_box_values, selection);
265 }
266 
268 {
269  listbox& list = find_widget<listbox>(get_window(), "unit_type_list", false);
270 
271  const std::vector<std::string> words = utils::split(text, ' ');
272 
273  if(words == last_words_)
274  return;
275  last_words_ = words;
276 
277  boost::dynamic_bitset<> show_items;
278  show_items.resize(list.get_item_count(), true);
279 
280  if(!text.empty()) {
281  for(unsigned int i = 0; i < list.get_item_count(); i++) {
282  grid* row = list.get_row_grid(i);
283 
284  grid::iterator it = row->begin();
285  label& type_label
286  = find_widget<label>(*it, "unit_type", false);
287  label& race_label
288  = find_widget<label>(*it, "race", false);
289 
290  assert(i < units_.size());
291  const std::string& unit_type_id = units_[i] ? units_[i]->id() : "";
292 
293  bool found = false;
294  for(const auto & word : words)
295  {
296  found = translation::ci_search(type_label.get_label().str(), word) ||
297  translation::ci_search(race_label.get_label().str(), word) ||
298  translation::ci_search(unit_type_id, word);
299 
300  if(!found) {
301  // one word doesn't match, we don't reach words.end()
302  break;
303  }
304  }
305 
306  show_items[i] = found;
307  }
308  }
309 
310  list.set_row_shown(show_items);
311 }
312 
314 {
316 
318 }
319 
321 {
322  window& window = *this->get_window();
323  menu_button& var_box = find_widget<menu_button>(&window, "variation_box", false);
324  variation_ = var_box.get_value_config()["variation_id"].str();
325 
327 }
328 
329 } // namespace dialogs
330 } // namespace gui2
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:79
Simple push button.
Definition: menu_button.hpp:41
iterator begin()
Definition: grid.hpp:479
unit_race::GENDER gender()
Gender choice from the user.
Definition: unit_create.hpp:54
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:1378
virtual void post_show(window &window) override
Inherited from modal_dialog.
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
Label showing a text.
Definition: label.hpp:32
int get_selected_row() const
Returns the first selected row.
Definition: listbox.cpp:276
std::string str
Definition: statement.cpp:110
const unit_type_map & types() const
Definition: types.hpp:376
group< unit_race::GENDER > gender_toggle
Definition: unit_create.hpp:93
A single unit type that the player may recruit.
Definition: types.hpp:44
Class for a single line text area.
Definition: text_box.hpp:121
void update_displayed_type() const
Generic file dialog.
Definition: field-fwd.hpp:22
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:1151
unit_race::GENDER gender_
Definition: unit_create.hpp:68
The listbox class.
Definition: listbox.hpp:42
Base container class.
Definition: grid.hpp:30
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:100
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:136
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:66
Various uncategorised dialogs.
bool ci_search(const std::string &s1, const std::string &s2)
Definition: gettext.cpp:518
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:74
std::size_t i
Definition: function.cpp:933
virtual void pre_show(window &window) override
Inherited from modal_dialog.
Definition: unit_create.cpp:88
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
const t_string & get_label() const
bool empty() const
Definition: tstring.hpp:182
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:164
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:186
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:62
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
Definition: listbox.cpp:144
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