15 #define GETTEXT_DOMAIN "wesnoth-lib"
53 #define LOG_DP LOG_STREAM(info, log_display)
61 static std::pair sort_default{ std::string{
"unit_name"}, sort_order::type::ascending };
62 static utils::optional<decltype(sort_default)> sort_last;
72 , cancel_label_(
_("Cancel"))
85 void dump_recall_list_to_console(
const T& units)
92 for(const auto& u_ptr : units) {
93 LOG_DP <<
"\tunit[" << (idx++) <<
"]: " << u_ptr->id() <<
" name = '" << u_ptr->name() <<
"'";
97 std::string get_title_suffix(
int side_num)
105 int controlled_recruiters = 0;
108 ++controlled_recruiters;
112 std::stringstream
msg;
113 if(controlled_recruiters >= 2) {
116 msg <<
" (" << leader->name() <<
")";
129 listbox& list = find_widget<listbox>(
"main_list");
133 find_widget<button>(
"show_help"),
143 find_widget<label>(
"title").set_label(
title_);
144 find_widget<button>(
"ok").set_label(
ok_label_);
146 find_widget<button>(
"dismiss").set_visible(
false);
147 find_widget<button>(
"rename").set_visible(
false);
148 find_widget<grid>(
"variation_gender_grid").set_visible(
false);
149 find_widget<grid>(
"_header_grid").set_visible(
show_header_ );
170 column[
"use_markup"] =
"true";
172 column[
"label"] = gen(
i);
173 if (
id !=
"unit_image") {
174 filter_fmt << column[
"label"];
176 row_data.emplace(
id, column);
183 const auto [sorter_id, order] = sort_last.value_or(sort_default);
189 listbox& list = find_widget<listbox>(
"main_list");
198 std::string name = selected_unit.
name();
200 if(gui2::dialogs::edit_text::execute(
_(
"Rename Unit"),
_(
"Name:"), name)) {
201 selected_unit.
rename(name);
206 std::ostringstream filter_text;
207 filter_text << selected_unit.
type_name() <<
" " << name <<
" " << std::to_string(selected_unit.
level());
208 for(
const std::string& trait : selected_unit.
trait_names()) {
209 filter_text <<
" " << trait;
220 LOG_DP <<
"Recall list units:"; dump_recall_list_to_console(unit_list);
222 listbox& list = find_widget<listbox>(
"main_list");
234 ?
_(
"Do you really want to dismiss him?")
235 :
_(
"Do you really want to dismiss her?"));
237 }
else if(u.
level() > 1) {
239 ?
_(
"Do you really want to dismiss him?")
240 :
_(
"Do you really want to dismiss her?"));
244 ?
_(
"Do you really want to dismiss him?")
245 :
_(
"Do you really want to dismiss her?"));
265 LOG_DP <<
"Dismissing a unit, side = " << u.
side() <<
", id = '" << u.
id() <<
"'";
266 LOG_DP <<
"That side's recall list:";
271 assert(dismissed_unit);
291 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
304 listbox& list = find_widget<listbox>(
"main_list");
306 sort_last.emplace(sorter->id(), order);
318 const std::string& text = find_widget<text_box>(
"filter_box").get_value();
319 auto& list = find_widget<listbox>(
"main_list");
325 find_widget<button>(
"rename").set_active(shown > 0);
326 find_widget<button>(
"dismiss").set_active(shown > 0);
333 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
345 variation_ = find_widget<menu_button>(
"variation_box").get_value_config()[
"variation_id"].str();
347 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
360 auto dlg = std::make_unique<units_dialog>();
362 const auto type_gen = [](
const auto&
type) {
363 std::string type_name =
type->type_name();
364 if(type_name !=
type->id()) {
365 type_name +=
" (" +
type->id() +
")";
370 const auto race_gen = [](
const auto&
type) {
371 return type->race()->plural_name();
374 const auto populate_variations = [&dlg](
const unit_type* ut) {
377 std::vector<config> var_box_values;
378 var_box_values.emplace_back(
"label",
_(
"unit_variation^Default Variation"),
"variation_id",
"");
380 const auto& uvars = ut->variation_types();
384 unsigned n = 0, selection = 0;
386 for(
const auto& [uv_id, uv] : uvars) {
389 std::string uv_label;
390 if(!uv.variation_name().empty()) {
391 uv_label = uv.variation_name() +
" (" + uv_id +
")";
392 }
else if(!uv.type_name().empty() && uv.type_name() != ut->type_name()) {
393 uv_label = uv.type_name() +
" (" + uv_id +
")";
398 var_box_values.emplace_back(
"label", uv_label,
"variation_id", uv_id);
400 if(uv_id == dlg->variation()) {
408 dlg->clear_variation();
411 var_box.
set_values(var_box_values, selection);
414 dlg->set_title(
_(
"Create Unit"))
423 auto&
group = dlg->get_toggle();
428 dlg->update_gender(
gender);
432 dlg->update_variation();
436 dlg->set_column(
"unit_name", types_list, type_gen,
true)
437 .set_column(
"unit_details", types_list, race_gen,
true)
438 .set_update_function([&](
const std::size_t
index) {
447 populate_variations(ut);
449 const auto&
g = dlg->gender();
454 const auto& var = dlg->variation();
467 const std::vector<const unit_type*>& recruit_list,
470 auto dlg = std::make_unique<units_dialog>();
471 dlg->set_title(
_(
"Recruit Unit") + get_title_suffix(
team.
side()))
472 .set_ok_label(
_(
"Recruit"))
473 .set_help_topic(
"recruit_and_recall")
474 .set_row_num(recruit_list.size())
475 .show_all_headers(
false)
476 .set_column(
"unit_image", recruit_list, [&
team](
const auto& recruit) {
477 std::string image_string = recruit->image();
478 image_string +=
"~RC(" + recruit->flag_rgb() +
">" +
team.
color() +
")";
479 image_string +=
"~SCALE_INTO(72,72)";
482 .
set_column(
"unit_details", recruit_list, [](
const auto& recruit) {
494 auto dlg = std::make_unique<units_dialog>();
495 dlg->set_title(
_(
"Unit List"))
496 .set_ok_label(
_(
"Scroll To"))
497 .set_help_topic(
"..units")
498 .set_row_num(unit_list.size());
503 dlg->rename_unit(unit_list);
506 dlg->set_column(
"unit_name", unit_list, [](
const auto&
unit) {
510 dlg->set_column(
"unit_details", unit_list, [](
const auto&
unit) {
514 dlg->set_column(
"unit_level", unit_list,
515 [](
const auto&
unit) {
519 return std::tuple(u->level(), -
static_cast<int>(u->experience_to_advance()));
522 dlg->set_column(
"unit_moves", unit_list,
523 [](
const auto&
unit) {
527 return u->movement_left();
530 dlg->set_column(
"unit_hp", unit_list,
531 [](
const auto&
unit) {
535 return u->hitpoints();
538 dlg->set_column(
"unit_xp", unit_list,
539 [](
const auto&
unit) {
540 std::stringstream exp_str;
551 return u->experience() + u->max_experience();
553 dlg->set_column(
"unit_status", unit_list, [](
const auto&
unit) {
556 return "misc/petrified.png";
560 return "misc/poisoned.png";
564 return "misc/slowed.png";
568 return "misc/invisible.png";
573 dlg->set_column(
"unit_traits", unit_list, [](
const auto&
unit) {
576 dlg->set_update_function([&](
const std::size_t
index) {
586 std::vector<unit_const_ptr>& recall_list,
604 auto dlg = std::make_unique<units_dialog>();
605 dlg->set_title(
_(
"Recall Unit") + get_title_suffix(
team.
side()))
606 .set_ok_label(
_(
"Recall"))
607 .set_help_topic(
"recruit_and_recall")
608 .set_row_num(recall_list.size());
613 dlg->rename_unit(recall_list);
619 dlg->dismiss_unit(recall_list, team);
622 dlg->set_column(
"unit_image", recall_list, [recallable](
const auto&
unit) {
624 if(
unit->
can_recruit()) { mods +=
"~BLIT(" + unit::leader_crown() +
")"; }
626 mods +=
"~BLIT(" + overlay +
")";
628 if(!recallable(
unit)) { mods +=
"~GS()"; }
629 mods +=
"~SCALE_INTO(72,72)";
633 dlg->set_column(
"unit_name", recall_list,
634 [recallable](
const auto&
unit) {
640 dlg->set_column(
"unit_details", recall_list,
641 [recallable, &
team](
const auto&
unit) {
642 std::stringstream details;
645 return details.str();
649 dlg->set_column(
"unit_moves", recall_list,
650 [](
const auto&
unit) {
653 [](
const auto& recall) {
return recall->movement_left(); });
655 dlg->set_column(
"unit_level", recall_list,
656 [recallable](
const auto&
unit) {
659 [](
const auto& recall) {
660 return std::tuple(recall->level(), -
static_cast<int>(recall->experience_to_advance()));
663 dlg->set_column(
"unit_hp", recall_list,
664 [](
const auto&
unit) {
667 [](
const auto& recall) {
return recall->hitpoints(); });
669 dlg->set_column(
"unit_xp", recall_list,
670 [](
const auto&
unit) {
671 std::stringstream exp_str;
679 [](
const auto& recall) {
682 return recall->experience() + recall->max_experience();
685 dlg->set_column(
"unit_traits", recall_list,
686 [recallable](
const auto&
unit) {
689 traits += (traits.empty() ?
"" :
"\n") + trait;
693 [](
const auto& recall) {
694 return !recall->trait_names().empty() ? recall->trait_names().front().str() :
"";
697 dlg->show_header(
"unit_status",
false);
699 dlg->set_tooltip_generator(recall_list, [&](
const auto& recall) {
700 if (!recallable(recall)) {
703 return _(
"This unit cannot be recalled because you will not have enough gold at this point in your plan.");
705 return _(
"This unit cannot be recalled because you do not have enough gold.");
708 return std::string();
712 dlg->set_update_function([&](
const std::size_t
index) {
virtual const unit_map & units() const override
Main class to show messages to the user.
@ yes_no_buttons
Shows a yes and no button.
Abstract base class for all modal dialogs.
int get_retval() const
Returns the cached window exit code.
void filter_text_changed()
void show_list(listbox &list)
static std::unique_ptr< units_dialog > build_recruit_dialog(const std::vector< const unit_type * > &recruit_list, const team &team)
std::vector< std::string > filter_options_
units_dialog & set_ok_label(const std::string &ok_label)
units_dialog & show_all_headers(const bool show=true)
std::function< std::string(std::size_t)> tooltip_gen_
std::function< void(const std::size_t)> update_view_
virtual void post_show() override
Actions to be taken after the window has been shown.
void rename_unit(std::vector< unit_const_ptr > &unit_list)
units_dialog & set_help_topic(const std::string &topic_id)
units_dialog & set_update_function(const std::function< void(const std::size_t)> &update_func)
Called to update the UI components, such as the preview pane, gender toggles and variation box.
unit_race::GENDER gender_
static std::unique_ptr< units_dialog > build_unit_list_dialog(std::vector< unit_const_ptr > &units_list)
units_dialog & set_row_num(const std::size_t row_num)
static std::unique_ptr< units_dialog > build_create_dialog(const std::vector< const unit_type * > &types_list)
void dismiss_unit(std::vector< unit_const_ptr > &unit_list, const team &team)
std::map< std::string_view, std::function< std::string(std::size_t)> > column_generators_
units_dialog & set_column(std::string_view id, const std::vector< Value > &container, const Generator &generator, const bool use_as_sorter=false)
Corresponding to each widget in the row with id 'id', there is a lambda that generates the correspond...
virtual void pre_show() override
Actions to be taken before showing the window.
void list_item_clicked()
Callbacks.
unit_race::GENDER gender() const
Gender choice from the user.
std::string cancel_label_
static std::unique_ptr< units_dialog > build_recall_dialog(std::vector< unit_const_ptr > &recall_list, const team &team)
void update_gender(const unit_race::GENDER val)
void add_member(selectable_item *w, const T &value)
Adds a widget/value pair to the group map.
void set_member_states(const T &value)
Sets the toggle values for all widgets besides the one associated with the specified value to false.
void set_callback_on_value_change(std::function< void(widget &, const T)> func)
Sets a common callback function for all members.
void set_members_enabled(std::function< bool(const T &)> predicate)
Wrapper for enabling or disabling member widgets.
grid & add_row(const widget_item &item, const int index=-1)
When an item in the list is selected by the user we need to update the state.
const grid * get_row_grid(const unsigned row) const
Returns the grid of the wanted row.
void set_active_sorter(std::string_view id, sort_order::type order, bool select_first=false)
Sorts the listbox by a pre-set sorting option.
std::pair< widget *, sort_order::type > get_active_sorter() const
Returns a widget pointer to the active sorter, along with its corresponding order.
void remove_row(const unsigned row, unsigned count=1)
Removes a row in the listbox.
void clear()
Removes all the rows in the listbox, clearing it.
int get_selected_row() const
Returns the first selected row.
unsigned get_item_count() const
Returns the number of items in the listbox.
A widget that allows the user to input text in single line.
void set_retval(const int retval, const bool close_window=true)
Sets there return value of the window.
void keyboard_capture(widget *widget)
void invalidate_layout()
Updates the size of the window.
void add_to_keyboard_chain(widget *widget)
Adds the widget to the keyboard chain.
static const std::string & type()
Static type getter that does not rely on the widget being constructed.
std::shared_ptr< wb::manager > get_whiteboard() const
unit_ptr find_if_matches_id(const std::string &unit_id)
Find a unit by id.
static config get_disband(const std::string &unit_id)
static bool run_and_throw(const std::string &commandname, const config &data, action_spectator &spectator=get_default_spectator())
const std::string & str() const
This class stores all the data for a single 'side' (in game nomenclature).
const std::string & color() const
bool is_local_human() const
recall_list_manager & recall_list()
const std::set< std::string > & recruits() const
Container associating units to locations.
unit_iterator find_leader(int side)
A single unit type that the player may recruit.
const unit_type & get_gender_unit_type(const std::string &gender) const
Returns a gendered variant of this unit_type.
const unit_type & get_variation(const std::string &id) const
bool has_gender_variation(const unit_race::GENDER gender) const
This class represents a single unit of a specific type.
static std::string _(const char *str)
bool invisible(const map_location &loc, bool see_all=true) const
int max_hitpoints() const
The max number of hitpoints this unit can have.
bool incapacitated() const
Check if the unit has been petrified.
int level() const
The current level of this unit.
const t_string & type_name() const
Gets the translatable name of this unit's type.
int recall_cost() const
How much gold it costs to recall this unit, or -1 if the side's default recall cost is used.
void rename(const std::string &name)
Attempts to rename this unit's translatable display name, taking the 'unrenamable' flag into account.
int hitpoints() const
The current number of hitpoints this unit has.
bool slowed() const
Check if the unit has been slowed.
int experience() const
The current number of experience points this unit has.
bool can_recruit() const
Whether this unit can recruit other units - ie, are they a leader unit.
const std::string & id() const
Gets this unit's id.
int side() const
The side this unit belongs to.
bool poisoned() const
Check if the unit has been poisoned.
int max_experience() const
The max number of experience points this unit can have.
unit_race::GENDER gender() const
The gender of this unit.
const t_string & name() const
Gets this unit's translatable display name.
bool can_advance() const
Checks whether this unit has any options to advance to.
color_t xp_color() const
Color for this unit's XP.
color_t hp_color() const
Color for this unit's current hitpoints.
std::string image_mods() const
Gets an IPF string containing all IPF image mods.
const std::vector< std::string > & overlays() const
Get the unit's overlay images.
std::string absolute_image() const
The name of the file to game_display (used in menus).
const map_location & get_location() const
The current map location this unit is at.
int movement_left() const
Gets how far a unit can move, considering the incapacitated flag.
int total_movement() const
The maximum moves this unit has.
const std::vector< t_string > & trait_names() const
Gets the names of the currently registered traits.
bool loyal() const
Gets whether this unit is loyal - ie, it costs no upkeep.
T end(const std::pair< T, T > &p)
Standard logging facilities (interface).
#define log_scope2(domain, description)
const std::string unicode_en_dash
REGISTER_DIALOG(editor_edit_unit)
void connect_signal_notify_modified(dispatcher &dispatcher, const signal_notification &signal)
Connects a signal handler for getting a notification upon modification.
void connect_signal_mouse_left_click(dispatcher &dispatcher, const signal &signal)
Connects a signal handler for a left mouse button click.
std::map< std::string, widget_item > widget_data
std::map< std::string, t_string > widget_item
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
@ OK
Dialog was closed with the OK button.
@ CANCEL
Dialog was closed with the CANCEL button.
void show_help(const std::string &show_topic)
Open the help browser, show topic with id show_topic.
std::string span_color(const color_t &color, Args &&... data)
play_controller * controller
auto make_ci_matcher(std::string_view filter_text)
Returns a function which performs locale-aware case-insensitive search.
std::string format_level_string(const int level, bool recallable)
std::string format_cost_string(int unit_recall_cost, const int team_recall_cost)
std::string maybe_inactive(const std::string &str, bool active)
std::string format_movement_string(const int moves_left, const int moves_max)
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
std::size_t index(std::string_view str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
std::shared_ptr< const unit > unit_const_ptr
Applies the planned unit map for the duration of the struct's life.
static map_location::direction n
static lg::log_domain log_display("display")