15 #define GETTEXT_DOMAIN "wesnoth-lib"
53 #define LOG_DP LOG_STREAM(info, log_display)
61 std::pair sort_default{ std::string{
"unit_name"}, sort_order::type::ascending };
62 utils::optional<decltype(sort_default)> sort_last;
64 std::string star(
bool starred)
67 return starred ?
"\u2605" :
"\u2606";
79 , cancel_label_(
_("Cancel"))
81 , show_dismiss_(false)
82 , show_mark_favorite_(false)
83 , show_variations_(false)
84 , sort_order_(sort_default)
90 for(
widget* sort_toggle : find_widget<grid>(
"_header_grid")) {
93 if(!sort_toggle->id().empty()) {
102 void dump_recall_list_to_console(
const T& units)
109 for(const auto& u_ptr : units) {
110 LOG_DP <<
"\tunit[" << (idx++) <<
"]: " << u_ptr->id() <<
" name = '" << u_ptr->name() <<
"'";
114 std::string get_title_suffix(
int side_num)
122 int controlled_recruiters = 0;
125 ++controlled_recruiters;
129 std::stringstream
msg;
130 if(controlled_recruiters >= 2) {
133 msg <<
" (" << leader->name() <<
")";
146 listbox& list = find_widget<listbox>(
"main_list");
150 find_widget<button>(
"show_help"),
158 find_widget<label>(
"title").set_label(
title_);
159 find_widget<button>(
"ok").set_label(
ok_label_);
162 find_widget<button>(
"rename").set_visible(
show_rename_);
169 find_widget<menu_button>(
"variation_box"), [
this](
auto&&...) {
update_variation(); });
202 std::vector<std::string> filter_keys;
204 column[
"use_markup"] =
"true";
206 column[
"label"] = gen(
i);
208 filter_keys.emplace_back(column[
"label"]);
210 row_data.emplace(
id, column);
219 const auto [sorter_id, order] = sort_last.value_or(
sort_order_);
229 listbox& list = find_widget<listbox>(
"main_list");
238 std::string name = selected_unit.
name();
240 if(gui2::dialogs::edit_text::execute(
_(
"Rename Unit"),
_(
"Name:"), name)) {
241 selected_unit.
rename(name);
255 LOG_DP <<
"Recall list units:"; dump_recall_list_to_console(unit_list);
257 listbox& list = find_widget<listbox>(
"main_list");
274 ?
_(
"Do you really want to dismiss him?")
275 :
_(
"Do you really want to dismiss her?"));
277 }
else if(u.
level() > 1) {
279 ?
_(
"Do you really want to dismiss him?")
280 :
_(
"Do you really want to dismiss her?"));
284 ?
_(
"Do you really want to dismiss him?")
285 :
_(
"Do you really want to dismiss her?"));
308 LOG_DP <<
"Dismissing a unit, side = " << u.
side() <<
", id = '" << u.
id() <<
"'";
309 LOG_DP <<
"That side's recall list:";
314 assert(dismissed_unit);
327 listbox& list = find_widget<listbox>(
"main_list");
353 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
364 listbox& list = find_widget<listbox>(
"main_list");
366 sort_last.emplace(sorter->id(), order);
378 const std::size_t shown = find_widget<listbox>(
"main_list")
384 find_widget<button>(
"rename").set_active(shown > 0);
385 find_widget<button>(
"dismiss").set_active(shown > 0);
392 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
402 variation_ = find_widget<menu_button>(
"variation_box").get_value_config()[
"variation_id"].str();
404 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
415 auto dlg = std::make_unique<units_dialog>();
417 const auto type_gen = [](
const auto&
type) {
418 std::string type_name =
type->type_name();
419 if(type_name !=
type->id()) {
420 type_name +=
" (" +
type->id() +
")";
425 const auto race_gen = [](
const auto&
type) {
426 return type->race()->plural_name();
429 const auto populate_variations = [&dlg](
const unit_type& ut) {
432 std::vector<config> var_box_values;
433 var_box_values.emplace_back(
"label",
_(
"unit_variation^Default Variation"),
"variation_id",
"");
435 const auto& uvars = ut.variation_types();
439 unsigned n = 0, selection = 0;
441 for(
const auto& [uv_id, uv] : uvars) {
444 std::string uv_label;
445 if(!uv.variation_name().empty()) {
446 uv_label = uv.variation_name() +
" (" + uv_id +
")";
447 }
else if(!uv.type_name().empty() && uv.type_name() != ut.type_name()) {
448 uv_label = uv.type_name() +
" (" + uv_id +
")";
453 var_box_values.emplace_back(
"label", uv_label,
"variation_id", uv_id);
455 if(uv_id == dlg->variation()) {
463 dlg->clear_variation();
466 var_box.
set_values(var_box_values, selection);
469 dlg->set_title(
_(
"Create Unit"))
481 dlg->on_modified([populate_variations, &dlg, &types_list](std::size_t
index) ->
const auto& {
484 if (dlg->is_selected() && (
static_cast<int>(
index) == dlg->get_selected_index())) {
485 dlg->get_toggle().set_member_states(dlg->gender());
487 dlg->get_toggle().set_members_enabled(
488 [ut](const unit_race::GENDER& gender) { return ut->has_gender_variation(gender); });
491 populate_variations(*ut);
493 const auto&
g = dlg->gender();
494 if(ut->has_gender_variation(
g)) {
495 ut = &ut->get_gender_unit_type(
g);
498 const auto& var = dlg->variation();
500 ut = &ut->get_variation(var);
510 const std::vector<const unit_type*>& recruit_list,
515 auto dlg = std::make_unique<units_dialog>();
516 auto set_column = dlg->make_column_builder(recruit_list);
518 set_column(
"unit_image", [&](
const auto& recruit) {
519 std::string image_string = recruit->icon();
520 if (image_string.empty()) {
521 image_string = recruit->image();
523 image_string +=
"~RC(" + recruit->flag_rgb() +
">" +
team.
color() +
")";
524 image_string +=
"~SCALE_INTO(72,72)";
526 if (!err_msgs_map[recruit].empty()) {
527 image_string +=
"~GS()";
532 set_column(
"unit_details", [&](
const auto& recruit) {
534 bool recruitable = err_msgs_map[recruit].empty();
540 dlg->set_title(
_(
"Recruit Unit") + get_title_suffix(
team.
side()))
547 return err_msgs_map[recruit_list[
index]];
550 dlg->
on_modified([&recruit_list](std::size_t
index) ->
const auto& {
return *recruit_list[
index]; });
557 auto dlg = std::make_unique<units_dialog>();
558 dlg->set_title(
_(
"Unit List"))
559 .set_ok_label(
_(
"Scroll To"))
560 .set_help_topic(
"..units")
561 .set_row_num(unit_list.size())
562 .set_show_rename(
true)
563 .set_show_favorite(
true);
568 dlg->rename_unit(unit_list);
574 dlg->toggle_favorite(unit_list);
577 auto set_column = dlg->make_column_builder(unit_list);
579 set_column(
"unit_favorite", [](
const auto&
unit) {
583 set_column(
"unit_name",
584 [](
const auto&
unit) {
588 set_column(
"unit_details",
589 [](
const auto&
unit) {
593 set_column(
"unit_level",
594 [](
const auto&
unit) {
597 [](
const auto&
unit) {
601 set_column(
"unit_moves",
602 [](
const auto&
unit) {
605 [](
const auto&
unit) {
609 set_column(
"unit_hp",
610 [](
const auto&
unit) {
613 [](
const auto&
unit) {
617 set_column(
"unit_xp",
618 [](
const auto&
unit) {
619 std::stringstream exp_str;
621 exp_str << unit->experience() <<
"/" << unit->max_experience();
623 exp_str << font::unicode_en_dash;
627 [](
const auto&
unit) {
633 set_column(
"unit_status", [](
const auto&
unit) {
636 return
"misc/petrified.png";
640 return
"misc/poisoned.png";
644 return
"misc/slowed.png";
648 return
"misc/invisible.png";
654 set_column(
"unit_traits", [](
const auto&
unit) {
658 dlg->set_filter_generator([&unit_list](std::size_t
index) {
660 std::vector<std::string> filter_keys;
664 filter_keys.emplace_back(std::to_string(
unit->
level()));
667 if(
const auto* race =
unit->
race()) {
668 filter_keys.emplace_back(race->name(
unit->
gender()));
669 filter_keys.emplace_back(race->plural_name());
673 filter_keys.emplace_back(trait);
679 dlg->on_modified([&unit_list, &rename](std::size_t
index) ->
const auto& {
689 std::vector<unit_const_ptr>& recall_list,
699 const auto recallable = [wb_gold, &
team](
const unit&
unit) {
705 auto dlg = std::make_unique<units_dialog>();
706 dlg->set_title(
_(
"Recall Unit") + get_title_suffix(
team.
side()))
707 .set_ok_label(
_(
"Recall"))
708 .set_help_topic(
"recruit_and_recall")
709 .set_row_num(recall_list.size())
710 .set_show_rename(
true)
711 .set_show_dismiss(
true)
712 .set_show_favorite(
true);
717 dlg->rename_unit(recall_list);
723 dlg->dismiss_unit(recall_list,
team);
729 dlg->toggle_favorite(recall_list);
732 auto set_column = dlg->make_column_builder(recall_list);
734 set_column(
"unit_favorite", [](
const auto&
unit) {
738 set_column(
"unit_image", [recallable](
const auto&
unit) {
740 if(
unit->
can_recruit()) { mods +=
"~BLIT(" + unit::leader_crown() +
")"; }
742 mods +=
"~BLIT(" + overlay +
")";
744 if(!recallable(*
unit)) { mods +=
"~GS()"; }
745 mods +=
"~SCALE_INTO(72,72)";
749 set_column(
"unit_name",
750 [recallable](
const auto&
unit) {
754 [](
const auto&
unit) {
758 set_column(
"unit_details",
759 [recallable, &
team](
const auto&
unit) {
760 std::stringstream details;
763 if (recallable(*
unit)) {
768 return details.str();
770 [](
const auto&
unit) {
774 set_column(
"unit_moves",
775 [recallable](
const auto&
unit) {
779 [](
const auto&
unit) {
783 set_column(
"unit_level",
784 [recallable](
const auto&
unit) {
787 [](
const auto&
unit) {
791 set_column(
"unit_hp",
792 [recallable](
const auto&
unit) {
796 [](
const auto&
unit) {
800 set_column(
"unit_xp",
801 [recallable](
const auto&
unit) {
809 [](
const auto&
unit) {
815 set_column(
"unit_traits",
816 [recallable](
const auto&
unit) {
819 traits += (traits.empty() ?
"" :
"\n") + trait;
823 [](
const auto&
unit) {
828 dlg->set_sort_by(std::pair(
"unit_level", sort_order::type::descending));
830 dlg->set_tooltip_generator([recallable, wb_gold, &recall_list](std::size_t
index) {
831 if(recallable(*recall_list[
index])) {
832 return std::string();
837 return _(
"This unit cannot be recalled because you will not have enough gold at this point in your plan.");
839 return _(
"This unit cannot be recalled because you do not have enough gold.");
843 dlg->set_filter_generator([&recall_list](std::size_t
index) {
845 std::vector<std::string> filter_keys;
849 filter_keys.emplace_back(std::to_string(
unit->
level()));
852 if(
const auto* race =
unit->
race()) {
853 filter_keys.emplace_back(race->name(
unit->
gender()));
854 filter_keys.emplace_back(race->plural_name());
858 filter_keys.emplace_back(trait);
864 dlg->on_modified([&recall_list, &rename](std::size_t
index) ->
const auto& {
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.
units_dialog & set_tooltip_generator(const Generator &generator)
Sets the generator function for the tooltips.
void show_list(listbox &list)
std::pair< std::string, sort_order::type > sort_order_
std::function< std::vector< std::string >std::size_t)> filter_gen_
std::map< const unit_type *, t_string > recruit_msgs_map
units_dialog & set_ok_label(const std::string &ok_label)
std::vector< std::vector< std::string > > filter_options_
auto make_column_builder(const std::vector< Value > &list)
Creates a generator function which registers secondary generator and sorter functions for the list co...
std::function< std::string(std::size_t)> tooltip_gen_
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_show_variations(bool show=true)
group< unit_race::GENDER > & get_toggle()
unit_race::GENDER gender_
void filter_text_changed(const std::string &text)
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)
void toggle_favorite(std::vector< unit_const_ptr > &unit_list)
void on_modified(const Func &f)
Registers an function which will fired on NOTIFY_MODIFIED dialog events.
std::map< std::string_view, std::function< std::string(std::size_t)> > column_generators_
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_recruit_dialog(const std::vector< const unit_type * > &recruit_list, recruit_msgs_map &err_msgs_map, const team &team)
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)
bool fire(const ui_event event, widget &target)
Fires an event which has no extra parameters.
void on_modified(const Func &func)
Sets a common callback function for all members.
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.
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.
bool select_row(const unsigned row, const bool select=true)
Selects a row.
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.
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.
static std::string alignment_description(unit_alignments::type align, unit_race::GENDER gender=unit_race::MALE)
Implementation detail of unit_type::alignment_description.
This class represents a single unit of a specific type.
static std::string _(const char *str)
void set_favorite(bool favorite)
bool invisible(const map_location &loc, bool see_all=true) const
int max_hitpoints() const
The max number of hitpoints this unit can have.
unit_alignments::type alignment() const
The alignment of this unit.
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.
bool unrenamable() const
Whether this unit can be renamed.
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.
const unit_race * race() const
Gets this unit's race.
int experience() const
The current number of experience points this unit has.
t_string block_dismiss_message() const
A message of why this unit cannot be dismissed.
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 dismissable() const
Whether this unit can be dismissed.
bool poisoned() const
Check if the unit has been poisoned.
unsigned int experience_to_advance() const
The number of experience points this unit needs to level up, or 0 if current XP > max XP.
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_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup)
Shows a transient message to the user.
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)
Applies Pango markup to the input specifying its display color.
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_movement_string(const int moves_left, const int moves_max, bool active)
std::string maybe_inactive(const std::string &str, bool active)
std::string format_cost_string(int unit_recall_cost, bool active)
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
The basic class for representing 8-bit RGB or RGBA colour values.
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")