The Battle for Wesnoth  1.17.0-dev
unit_recruit.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2016 - 2021
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 
17 #include "font/text_formatting.hpp"
20 #include "gui/widgets/button.hpp"
21 #include "gui/widgets/image.hpp"
22 #include "gui/widgets/label.hpp"
23 #include "gui/widgets/listbox.hpp"
25 #include "gui/widgets/settings.hpp"
26 #include "gui/widgets/text_box.hpp"
28 #include "gui/widgets/window.hpp"
29 #include "gettext.hpp"
30 #include "help/help.hpp"
31 #include "play_controller.hpp"
32 #include "resources.hpp"
33 #include "team.hpp"
34 #include "units/types.hpp"
35 #include "whiteboard/manager.hpp"
36 
37 #include <functional>
38 
39 namespace gui2::dialogs
40 {
41 
42 REGISTER_DIALOG(unit_recruit)
43 
44 unit_recruit::unit_recruit(std::map<const unit_type*, t_string>& recruit_map, team& team)
45  : recruit_list_()
46  , recruit_map_(recruit_map)
47  , team_(team)
48  , selected_index_(0)
49 {
50  for(const auto& pair : recruit_map) {
51  recruit_list_.push_back(pair.first);
52  }
53  // Ensure the recruit list is sorted by name
54  std::sort(recruit_list_.begin(), recruit_list_.end(), [](const unit_type* t1, const unit_type* t2) {
55  return t1->type_name().str() < t2->type_name().str();
56  });
57 
58 }
59 
60 static const color_t inactive_row_color(0x96, 0x96, 0x96);
61 
62 static inline std::string gray_if_unrecruitable(const std::string& text, const bool is_recruitable)
63 {
64  return is_recruitable ? text : font::span_color(inactive_row_color, text);
65 }
66 
67 // Compare unit_create::filter_text_change
68 void unit_recruit::filter_text_changed(const std::string& text)
69 {
70  listbox& list = find_widget<listbox>(get_window(), "recruit_list", false);
71 
72  const std::vector<std::string> words = utils::split(text, ' ');
73 
74  if(words == last_words_)
75  return;
76  last_words_ = words;
77 
78  boost::dynamic_bitset<> show_items;
79  show_items.resize(list.get_item_count(), true);
80 
81  if(!text.empty()) {
82  for(unsigned int i = 0; i < list.get_item_count(); i++) {
83  assert(i < recruit_list_.size());
84  const unit_type* type = recruit_list_[i];
85  if(!type) continue;
86 
87  bool found = false;
88  for(const auto & word : words)
89  {
90  // Search for the name in the local language.
91  // In debug mode, also search for the type id.
92  found = (game_config::debug && translation::ci_search(type->id(), word)) ||
93  translation::ci_search(type->type_name(), word);
94 
95  if(!found) {
96  // one word doesn't match, we don't reach words.end()
97  break;
98  }
99  }
100 
101  show_items[i] = found;
102  }
103  }
104 
105  list.set_row_shown(show_items);
106 }
107 
109 {
110  text_box* filter = find_widget<text_box>(&window, "filter_box", false, true);
112  std::bind(&unit_recruit::filter_text_changed, this, std::placeholders::_2));
113 
114  listbox& list = find_widget<listbox>(&window, "recruit_list", false);
115 
117 
118  window.keyboard_capture(filter);
119  window.add_to_keyboard_chain(&list);
120 
122  find_widget<button>(&window, "show_help", false),
123  std::bind(&unit_recruit::show_help, this));
124 
125  for(const auto& recruit : recruit_list_)
126  {
127  const t_string& error = recruit_map_[recruit];
128  std::map<std::string, string_map> row_data;
129  string_map column;
130 
131  std::string image_string = recruit->image() + "~RC(" + recruit->flag_rgb() + ">"
132  + team_.color() + ")";
133 
134  const bool is_recruitable = error.empty();
135 
136  const std::string cost_string = std::to_string(recruit->cost());
137 
138  column["use_markup"] = "true";
139  if(!error.empty()) {
140  // Just set the tooltip on every single element in this row.
141  column["tooltip"] = error;
142  }
143 
144  column["label"] = image_string + (is_recruitable ? "" : "~GS()");
145  row_data.emplace("unit_image", column);
146 
147  column["label"] = gray_if_unrecruitable(recruit->type_name(), is_recruitable);
148  row_data.emplace("unit_type", column);
149 
150  column["label"] = gray_if_unrecruitable(cost_string, is_recruitable);
151  row_data.emplace("unit_cost", column);
152 
153  grid& grid = list.add_row(row_data);
154  if(!is_recruitable) {
155  image *gold_icon = dynamic_cast<image*>(grid.find("gold_icon", false));
156  assert(gold_icon);
157  gold_icon->set_image(gold_icon->get_image() + "~GS()");
158  }
159  }
160 
162 }
163 
165 {
166  const int selected_row
167  = find_widget<listbox>(get_window(), "recruit_list", false).get_selected_row();
168 
169  if(selected_row == -1) {
170  return;
171  }
172 
173  find_widget<unit_preview_pane>(get_window(), "recruit_details", false)
174  .set_displayed_type(*recruit_list_[selected_row]);
175 }
176 
178 {
179  help::show_help("recruit_and_recall");
180 }
181 
183 {
184  if(get_retval() == retval::OK) {
185  selected_index_ = find_widget<listbox>(&window, "recruit_list", false)
186  .get_selected_row();
187  }
188 }
189 
190 } // namespace dialogs
void set_text_changed_callback(std::function< void(text_box_base *textbox, const std::string text)> cb)
Set the text_changed callback.
void show_help(const std::string &show_topic, int xloc, int yloc)
Open the help browser, show topic with id show_topic.
Definition: help.cpp:144
static const color_t inactive_row_color(0x96, 0x96, 0x96)
static l_noret error(LoadState *S, const char *why)
Definition: lundump.cpp:40
This file contains the window object, this object is a top level container which has the event manage...
t_string get_image() const
Wrapper for label.
Definition: image.hpp:66
STL namespace.
window * get_window() const
Returns a pointer to the dialog&#39;s window.
A single unit type that the player may recruit.
Definition: types.hpp:45
std::vector< const unit_type * > recruit_list_
A vector of unit types in the order listed in the UI.
Class for a single line text area.
Definition: text_box.hpp:141
The listbox class.
Definition: listbox.hpp:43
std::string span_color(const color_t &color)
Returns a Pango formatting string using the provided color_t object.
Base container class.
Definition: grid.hpp:31
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:72
virtual void post_show(window &window) override
Actions to be taken after the window has been shown.
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:187
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
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:141
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal_function &signal)
Connects a signal handler for a left mouse button click.
Definition: dispatcher.cpp:172
widget * find(const std::string &id, const bool must_be_active) override
See widget::find.
Definition: grid.cpp:656
unsigned get_item_count() const
Returns the number of items in the listbox.
Definition: listbox.cpp:133
void filter_text_changed(const std::string &text)
bool ci_search(const std::string &s1, const std::string &s2)
Definition: gettext.cpp:559
std::size_t i
Definition: function.cpp:967
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:68
const bool & debug
static int sort(lua_State *L)
Definition: ltablib.cpp:397
void set_image(const t_string &label)
Wrapper for set_label.
Definition: image.hpp:53
int get_retval() const
Returns the cached window exit code.
bool empty() const
Definition: tstring.hpp:187
const std::string & color() const
Definition: team.hpp:268
std::vector< std::string > split(const config_attribute_value &val)
Functions to load and save images from/to disk.
static std::string gray_if_unrecruitable(const std::string &text, const bool is_recruitable)
Dialog was closed with the OK button.
Definition: retval.hpp:35
std::vector< std::string > last_words_
const std::string & str() const
Definition: tstring.hpp:191
base class of top level items, the only item which needs to store the final canvases to draw on...
Definition: window.hpp:65
void set_row_shown(const unsigned row, const bool shown)
Makes a row visible or invisible.
Definition: listbox.cpp:145
std::map< const unit_type *, t_string > & recruit_map_