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;
72 , cancel_label_(
_("Cancel"))
74 , show_dismiss_(false)
75 , show_variations_(false)
76 , sort_order_(sort_default)
82 for(
widget* sort_toggle : find_widget<grid>(
"_header_grid")) {
85 if(!sort_toggle->id().empty()) {
94 void dump_recall_list_to_console(
const T& units)
101 for(const auto& u_ptr : units) {
102 LOG_DP <<
"\tunit[" << (idx++) <<
"]: " << u_ptr->id() <<
" name = '" << u_ptr->name() <<
"'";
106 std::string get_title_suffix(
int side_num)
114 int controlled_recruiters = 0;
117 ++controlled_recruiters;
121 std::stringstream
msg;
122 if(controlled_recruiters >= 2) {
125 msg <<
" (" << leader->name() <<
")";
138 listbox& list = find_widget<listbox>(
"main_list");
142 find_widget<button>(
"show_help"),
150 find_widget<label>(
"title").set_label(
title_);
151 find_widget<button>(
"ok").set_label(
ok_label_);
154 find_widget<button>(
"rename").set_visible(
show_rename_);
160 find_widget<menu_button>(
"variation_box"), [
this](
auto&&...) {
update_variation(); });
193 std::vector<std::string> filter_keys;
195 column[
"use_markup"] =
"true";
197 column[
"label"] = gen(
i);
199 filter_keys.emplace_back(column[
"label"]);
201 row_data.emplace(
id, column);
210 const auto [sorter_id, order] = sort_last.value_or(
sort_order_);
220 listbox& list = find_widget<listbox>(
"main_list");
229 std::string name = selected_unit.
name();
231 if(gui2::dialogs::edit_text::execute(
_(
"Rename Unit"),
_(
"Name:"), name)) {
232 selected_unit.
rename(name);
246 LOG_DP <<
"Recall list units:"; dump_recall_list_to_console(unit_list);
248 listbox& list = find_widget<listbox>(
"main_list");
265 ?
_(
"Do you really want to dismiss him?")
266 :
_(
"Do you really want to dismiss her?"));
268 }
else if(u.
level() > 1) {
270 ?
_(
"Do you really want to dismiss him?")
271 :
_(
"Do you really want to dismiss her?"));
275 ?
_(
"Do you really want to dismiss him?")
276 :
_(
"Do you really want to dismiss her?"));
299 LOG_DP <<
"Dismissing a unit, side = " << u.
side() <<
", id = '" << u.
id() <<
"'";
300 LOG_DP <<
"That side's recall list:";
305 assert(dismissed_unit);
325 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
336 listbox& list = find_widget<listbox>(
"main_list");
338 sort_last.emplace(sorter->id(), order);
350 const std::size_t shown = find_widget<listbox>(
"main_list")
356 find_widget<button>(
"rename").set_active(shown > 0);
357 find_widget<button>(
"dismiss").set_active(shown > 0);
364 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
374 variation_ = find_widget<menu_button>(
"variation_box").get_value_config()[
"variation_id"].str();
376 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
387 auto dlg = std::make_unique<units_dialog>();
389 const auto type_gen = [](
const auto&
type) {
390 std::string type_name =
type->type_name();
391 if(type_name !=
type->id()) {
392 type_name +=
" (" +
type->id() +
")";
397 const auto race_gen = [](
const auto&
type) {
398 return type->race()->plural_name();
401 const auto populate_variations = [&dlg](
const unit_type& ut) {
404 std::vector<config> var_box_values;
405 var_box_values.emplace_back(
"label",
_(
"unit_variation^Default Variation"),
"variation_id",
"");
407 const auto& uvars = ut.variation_types();
411 unsigned n = 0, selection = 0;
413 for(
const auto& [uv_id, uv] : uvars) {
416 std::string uv_label;
417 if(!uv.variation_name().empty()) {
418 uv_label = uv.variation_name() +
" (" + uv_id +
")";
419 }
else if(!uv.type_name().empty() && uv.type_name() != ut.type_name()) {
420 uv_label = uv.type_name() +
" (" + uv_id +
")";
425 var_box_values.emplace_back(
"label", uv_label,
"variation_id", uv_id);
427 if(uv_id == dlg->variation()) {
435 dlg->clear_variation();
438 var_box.
set_values(var_box_values, selection);
441 dlg->set_title(
_(
"Create Unit"))
453 dlg->on_modified([populate_variations, &dlg, &types_list](std::size_t
index) ->
const auto& {
456 if (dlg->is_selected() && (
static_cast<int>(
index) == dlg->get_selected_index())) {
457 dlg->get_toggle().set_member_states(dlg->gender());
459 dlg->get_toggle().set_members_enabled(
460 [ut](const unit_race::GENDER& gender) { return ut->has_gender_variation(gender); });
463 populate_variations(*ut);
465 const auto&
g = dlg->gender();
466 if(ut->has_gender_variation(
g)) {
467 ut = &ut->get_gender_unit_type(
g);
470 const auto& var = dlg->variation();
472 ut = &ut->get_variation(var);
482 const std::vector<const unit_type*>& recruit_list,
487 auto dlg = std::make_unique<units_dialog>();
488 auto set_column = dlg->make_column_builder(recruit_list);
490 set_column(
"unit_image", [&](
const auto& recruit) {
491 std::string image_string = recruit->icon();
492 if (image_string.empty()) {
493 image_string = recruit->image();
495 image_string +=
"~RC(" + recruit->flag_rgb() +
">" +
team.
color() +
")";
496 image_string +=
"~SCALE_INTO(72,72)";
498 if (!err_msgs_map[recruit].empty()) {
499 image_string +=
"~GS()";
504 set_column(
"unit_details", [&](
const auto& recruit) {
506 bool recruitable = err_msgs_map[recruit].empty();
512 dlg->set_title(
_(
"Recruit Unit") + get_title_suffix(
team.
side()))
519 return err_msgs_map[recruit_list[
index]];
522 dlg->
on_modified([&recruit_list](std::size_t
index) ->
const auto& {
return *recruit_list[
index]; });
529 auto dlg = std::make_unique<units_dialog>();
530 dlg->set_title(
_(
"Unit List"))
531 .set_ok_label(
_(
"Scroll To"))
532 .set_help_topic(
"..units")
533 .set_row_num(unit_list.size())
534 .set_show_rename(
true);
539 dlg->rename_unit(unit_list);
542 auto set_column = dlg->make_column_builder(unit_list);
544 set_column(
"unit_name",
545 [](
const auto&
unit) {
549 set_column(
"unit_details",
550 [](
const auto&
unit) {
554 set_column(
"unit_level",
555 [](
const auto&
unit) {
558 [](
const auto&
unit) {
562 set_column(
"unit_moves",
563 [](
const auto&
unit) {
566 [](
const auto&
unit) {
570 set_column(
"unit_hp",
571 [](
const auto&
unit) {
574 [](
const auto&
unit) {
578 set_column(
"unit_xp",
579 [](
const auto&
unit) {
580 std::stringstream exp_str;
582 exp_str << unit->experience() <<
"/" << unit->max_experience();
584 exp_str << font::unicode_en_dash;
588 [](
const auto&
unit) {
594 set_column(
"unit_status", [](
const auto&
unit) {
597 return
"misc/petrified.png";
601 return
"misc/poisoned.png";
605 return
"misc/slowed.png";
609 return
"misc/invisible.png";
615 set_column(
"unit_traits", [](
const auto&
unit) {
619 dlg->set_filter_generator([&unit_list](std::size_t
index) {
621 std::vector<std::string> filter_keys;
625 filter_keys.emplace_back(std::to_string(
unit->
level()));
628 if(
const auto* race =
unit->
race()) {
629 filter_keys.emplace_back(race->name(
unit->
gender()));
630 filter_keys.emplace_back(race->plural_name());
634 filter_keys.emplace_back(trait);
640 dlg->on_modified([&unit_list, &rename](std::size_t
index) ->
const auto& {
650 std::vector<unit_const_ptr>& recall_list,
660 const auto recallable = [wb_gold, &
team](
const unit&
unit) {
666 auto dlg = std::make_unique<units_dialog>();
667 dlg->set_title(
_(
"Recall Unit") + get_title_suffix(
team.
side()))
668 .set_ok_label(
_(
"Recall"))
669 .set_help_topic(
"recruit_and_recall")
670 .set_row_num(recall_list.size())
671 .set_show_rename(
true)
672 .set_show_dismiss(
true);
677 dlg->rename_unit(recall_list);
683 dlg->dismiss_unit(recall_list,
team);
686 auto set_column = dlg->make_column_builder(recall_list);
688 set_column(
"unit_image", [recallable](
const auto&
unit) {
690 if(
unit->
can_recruit()) { mods +=
"~BLIT(" + unit::leader_crown() +
")"; }
692 mods +=
"~BLIT(" + overlay +
")";
694 if(!recallable(*
unit)) { mods +=
"~GS()"; }
695 mods +=
"~SCALE_INTO(72,72)";
699 set_column(
"unit_name",
700 [recallable](
const auto&
unit) {
704 [](
const auto&
unit) {
708 set_column(
"unit_details",
709 [recallable, &
team](
const auto&
unit) {
710 std::stringstream details;
713 if (recallable(*
unit)) {
718 return details.str();
720 [](
const auto&
unit) {
724 set_column(
"unit_moves",
725 [recallable](
const auto&
unit) {
729 [](
const auto&
unit) {
733 set_column(
"unit_level",
734 [recallable](
const auto&
unit) {
737 [](
const auto&
unit) {
741 set_column(
"unit_hp",
742 [recallable](
const auto&
unit) {
746 [](
const auto&
unit) {
750 set_column(
"unit_xp",
751 [recallable](
const auto&
unit) {
759 [](
const auto&
unit) {
765 set_column(
"unit_traits",
766 [recallable](
const auto&
unit) {
769 traits += (traits.empty() ?
"" :
"\n") + trait;
773 [](
const auto&
unit) {
778 dlg->set_sort_by(std::pair(
"unit_level", sort_order::type::descending));
780 dlg->set_tooltip_generator([recallable, wb_gold, &recall_list](std::size_t
index) {
781 if(recallable(*recall_list[
index])) {
782 return std::string();
787 return _(
"This unit cannot be recalled because you will not have enough gold at this point in your plan.");
789 return _(
"This unit cannot be recalled because you do not have enough gold.");
793 dlg->set_filter_generator([&recall_list](std::size_t
index) {
795 std::vector<std::string> filter_keys;
799 filter_keys.emplace_back(std::to_string(
unit->
level()));
802 if(
const auto* race =
unit->
race()) {
803 filter_keys.emplace_back(race->name(
unit->
gender()));
804 filter_keys.emplace_back(race->plural_name());
808 filter_keys.emplace_back(trait);
814 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 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)
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")