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)
81 for(
widget* sort_toggle : find_widget<grid>(
"_header_grid")) {
84 if(!sort_toggle->id().empty()) {
93 void dump_recall_list_to_console(
const T& units)
100 for(const auto& u_ptr : units) {
101 LOG_DP <<
"\tunit[" << (idx++) <<
"]: " << u_ptr->id() <<
" name = '" << u_ptr->name() <<
"'";
105 std::string get_title_suffix(
int side_num)
113 int controlled_recruiters = 0;
116 ++controlled_recruiters;
120 std::stringstream
msg;
121 if(controlled_recruiters >= 2) {
124 msg <<
" (" << leader->name() <<
")";
137 listbox& list = find_widget<listbox>(
"main_list");
141 find_widget<button>(
"show_help"),
149 find_widget<label>(
"title").set_label(
title_);
150 find_widget<button>(
"ok").set_label(
ok_label_);
153 find_widget<button>(
"rename").set_visible(
show_rename_);
159 find_widget<menu_button>(
"variation_box"), [
this](
auto&&...) {
update_variation(); });
189 column[
"use_markup"] =
"true";
191 column[
"label"] = gen(
i);
192 if (
id !=
"unit_image") {
193 filter_fmt << column[
"label"];
195 row_data.emplace(
id, column);
202 const auto [sorter_id, order] = sort_last.value_or(sort_default);
208 listbox& list = find_widget<listbox>(
"main_list");
217 std::string name = selected_unit.
name();
219 if(gui2::dialogs::edit_text::execute(
_(
"Rename Unit"),
_(
"Name:"), name)) {
220 selected_unit.
rename(name);
225 std::ostringstream filter_text;
226 filter_text << selected_unit.
type_name() <<
" " << name <<
" " << std::to_string(selected_unit.
level());
227 for(
const std::string& trait : selected_unit.
trait_names()) {
228 filter_text <<
" " << trait;
239 LOG_DP <<
"Recall list units:"; dump_recall_list_to_console(unit_list);
241 listbox& list = find_widget<listbox>(
"main_list");
253 ?
_(
"Do you really want to dismiss him?")
254 :
_(
"Do you really want to dismiss her?"));
256 }
else if(u.
level() > 1) {
258 ?
_(
"Do you really want to dismiss him?")
259 :
_(
"Do you really want to dismiss her?"));
263 ?
_(
"Do you really want to dismiss him?")
264 :
_(
"Do you really want to dismiss her?"));
284 LOG_DP <<
"Dismissing a unit, side = " << u.
side() <<
", id = '" << u.
id() <<
"'";
285 LOG_DP <<
"That side's recall list:";
290 assert(dismissed_unit);
310 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
321 listbox& list = find_widget<listbox>(
"main_list");
323 sort_last.emplace(sorter->id(), order);
335 auto& list = find_widget<listbox>(
"main_list");
336 const std::size_t shown = list.filter_rows_by(
340 find_widget<button>(
"rename").set_active(shown > 0);
341 find_widget<button>(
"dismiss").set_active(shown > 0);
348 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
358 variation_ = find_widget<menu_button>(
"variation_box").get_value_config()[
"variation_id"].str();
360 selected_index_ = find_widget<listbox>(
"main_list").get_selected_row();
371 auto dlg = std::make_unique<units_dialog>();
373 const auto type_gen = [](
const auto&
type) {
374 std::string type_name =
type->type_name();
375 if(type_name !=
type->id()) {
376 type_name +=
" (" +
type->id() +
")";
381 const auto race_gen = [](
const auto&
type) {
382 return type->race()->plural_name();
385 const auto populate_variations = [&dlg](
const unit_type& ut) {
388 std::vector<config> var_box_values;
389 var_box_values.emplace_back(
"label",
_(
"unit_variation^Default Variation"),
"variation_id",
"");
391 const auto& uvars = ut.variation_types();
395 unsigned n = 0, selection = 0;
397 for(
const auto& [uv_id, uv] : uvars) {
400 std::string uv_label;
401 if(!uv.variation_name().empty()) {
402 uv_label = uv.variation_name() +
" (" + uv_id +
")";
403 }
else if(!uv.type_name().empty() && uv.type_name() != ut.type_name()) {
404 uv_label = uv.type_name() +
" (" + uv_id +
")";
409 var_box_values.emplace_back(
"label", uv_label,
"variation_id", uv_id);
411 if(uv_id == dlg->variation()) {
419 dlg->clear_variation();
422 var_box.
set_values(var_box_values, selection);
425 dlg->set_title(
_(
"Create Unit"))
437 dlg->on_modified([populate_variations, &dlg, &types_list](std::size_t
index) ->
const auto& {
440 dlg->get_toggle().set_members_enabled(
443 populate_variations(*ut);
445 const auto&
g = dlg->gender();
450 const auto& var = dlg->variation();
462 const std::vector<const unit_type*>& recruit_list,
465 auto dlg = std::make_unique<units_dialog>();
466 auto set_column = dlg->make_column_builder(recruit_list);
468 set_column(
"unit_image", [&
team](
const auto& recruit) {
469 std::string image_string = recruit->icon();
470 if (image_string.empty()) {
471 image_string = recruit->image();
473 image_string +=
"~RC(" + recruit->flag_rgb() +
">" +
team.
color() +
")";
474 image_string +=
"~SCALE_INTO(72,72)";
478 set_column(
"unit_details", [](
const auto& recruit) {
482 dlg->set_title(
_(
"Recruit Unit") + get_title_suffix(
team.
side()))
483 .set_ok_label(
_(
"Recruit"))
484 .set_help_topic(
"recruit_and_recall")
485 .set_row_num(recruit_list.size());
487 dlg->on_modified([&recruit_list](std::size_t
index) ->
const auto& {
return *recruit_list[
index]; });
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())
499 .set_show_rename(
true);
504 dlg->rename_unit(unit_list);
507 auto set_column = dlg->make_column_builder(unit_list);
509 set_column(
"unit_name",
510 [](
const auto&
unit) {
514 set_column(
"unit_details",
515 [](
const auto&
unit) {
519 set_column(
"unit_level",
520 [](
const auto&
unit) {
523 [](
const auto&
unit) {
527 set_column(
"unit_moves",
528 [](
const auto&
unit) {
531 [](
const auto&
unit) {
535 set_column(
"unit_hp",
536 [](
const auto&
unit) {
539 [](
const auto&
unit) {
543 set_column(
"unit_xp",
544 [](
const auto&
unit) {
545 std::stringstream exp_str;
547 exp_str << unit->experience() <<
"/" << unit->max_experience();
549 exp_str << font::unicode_en_dash;
553 [](
const auto&
unit) {
559 set_column(
"unit_status", [](
const auto&
unit) {
562 return
"misc/petrified.png";
566 return
"misc/poisoned.png";
570 return
"misc/slowed.png";
574 return
"misc/invisible.png";
580 set_column(
"unit_traits", [](
const auto&
unit) {
584 dlg->on_modified([&unit_list, &rename](std::size_t
index) ->
const auto& {
594 std::vector<unit_const_ptr>& recall_list,
604 const auto recallable = [wb_gold, &
team](
const unit&
unit) {
610 auto dlg = std::make_unique<units_dialog>();
611 dlg->set_title(
_(
"Recall Unit") + get_title_suffix(
team.
side()))
612 .set_ok_label(
_(
"Recall"))
613 .set_help_topic(
"recruit_and_recall")
614 .set_row_num(recall_list.size())
615 .set_show_rename(
true)
616 .set_show_dismiss(
true);
621 dlg->rename_unit(recall_list);
627 dlg->dismiss_unit(recall_list,
team);
630 auto set_column = dlg->make_column_builder(recall_list);
632 set_column(
"unit_image", [recallable](
const auto&
unit) {
634 if(
unit->
can_recruit()) { mods +=
"~BLIT(" + unit::leader_crown() +
")"; }
636 mods +=
"~BLIT(" + overlay +
")";
638 if(!recallable(*
unit)) { mods +=
"~GS()"; }
639 mods +=
"~SCALE_INTO(72,72)";
643 set_column(
"unit_name",
644 [recallable](
const auto&
unit) {
648 [](
const auto&
unit) {
652 set_column(
"unit_details",
653 [recallable, &
team](
const auto&
unit) {
654 std::stringstream details;
657 return details.str();
659 [](
const auto&
unit) {
663 set_column(
"unit_moves",
664 [](
const auto&
unit) {
667 [](
const auto&
unit) {
671 set_column(
"unit_level",
672 [recallable](
const auto&
unit) {
675 [](
const auto&
unit) {
679 set_column(
"unit_hp",
680 [](
const auto&
unit) {
683 [](
const auto&
unit) {
687 set_column(
"unit_xp",
688 [](
const auto&
unit) {
690 return markup::span_color(unit->xp_color(), unit->experience(),
"/", unit->max_experience());
692 return markup::span_color(unit->xp_color(), font::unicode_en_dash);
695 [](
const auto&
unit) {
701 set_column(
"unit_traits",
702 [recallable](
const auto&
unit) {
705 traits += (traits.empty() ?
"" :
"\n") + trait;
709 [](
const auto&
unit) {
713 dlg->set_tooltip_generator([recallable, wb_gold, &recall_list](std::size_t
index) {
714 if(recallable(*recall_list[
index])) {
715 return std::string();
720 return _(
"This unit cannot be recalled because you will not have enough gold at this point in your plan.");
722 return _(
"This unit cannot be recalled because you do not have enough gold.");
726 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.
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)
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)
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_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.
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.
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.
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.
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.
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_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_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")