18 #define GETTEXT_DOMAIN "wesnoth-lib"
46 #include <boost/filesystem.hpp>
47 #include <boost/algorithm/string/replace.hpp>
70 if (x.first.find(
"INTERNAL") == std::string::npos) {
75 connect_signal<event::SDL_KEY_DOWN>(std::bind(
80 menu_button& alignments = find_widget<menu_button>(&win,
"alignment_list",
false);
88 menu_button& races = find_widget<menu_button>(&win,
"race_list",
false);
90 const std::string& race_name =
i.second.id();
98 menu_button& movetypes = find_widget<menu_button>(&win,
"movetype_list",
false);
107 menu_button& defenses = find_widget<menu_button>(&win,
"defense_list",
false);
121 menu_button& movement_costs = find_widget<menu_button>(&win,
"movement_costs_list",
false);
127 menu_button& resistances = find_widget<menu_button>(&win,
"resistances_list",
false);
128 menu_button& attack_types = find_widget<menu_button>(&win,
"attack_type_list",
false);
144 menu_button& usage_types = find_widget<menu_button>(&win,
"usage_list",
false);
152 multimenu_button& specials = find_widget<multimenu_button>(&win,
"weapon_specials_list",
false);
154 multimenu_button& abilities = find_widget<multimenu_button>(&win,
"abilities_list",
false);
158 range_group.
add_member(find_widget<toggle_button>(&win,
"range_melee",
false,
true),
"melee");
159 range_group.
add_member(find_widget<toggle_button>(&win,
"range_ranged",
false,
true),
"ranged");
164 find_widget<button>(&win,
"browse_unit_image",
false),
167 find_widget<button>(&win,
"preview_unit_image",
false),
170 find_widget<button>(&win,
"browse_portrait_image",
false),
173 find_widget<button>(&win,
"preview_portrait_image",
false),
176 find_widget<button>(&win,
"browse_small_profile_image",
false),
179 find_widget<button>(&win,
"preview_small_profile_image",
false),
182 find_widget<button>(&win,
"browse_attack_image",
false),
185 find_widget<button>(&win,
"preview_attack_image",
false),
188 button&
load = find_widget<button>(&win,
"load_unit_type",
false);
200 find_widget<button>(&win,
"load_movetype",
false),
204 find_widget<slider>(&win,
"resistances_slider",
false),
207 find_widget<menu_button>(&win,
"resistances_list",
false),
210 find_widget<toggle_button>(&win,
"resistances_checkbox",
false),
214 find_widget<slider>(&win,
"defense_slider",
false),
217 find_widget<menu_button>(&win,
"defense_list",
false),
220 find_widget<toggle_button>(&win,
"defense_checkbox",
false),
224 find_widget<slider>(&win,
"movement_costs_slider",
false),
227 find_widget<menu_button>(&win,
"movement_costs_list",
false),
230 find_widget<toggle_button>(&win,
"movement_costs_checkbox",
false),
246 find_widget<menu_button>(&win,
"atk_list",
false),
250 find_widget<text_box>(&win,
"name_box",
false),
253 find_widget<text_box>(&win,
"id_box",
false),
261 find_widget<button>(&win,
"atk_new",
false),
264 find_widget<button>(&win,
"atk_delete",
false),
267 find_widget<button>(&win,
"atk_next",
false),
270 find_widget<button>(&win,
"atk_prev",
false),
276 listbox& selector = find_widget<listbox>(&win,
"tabs",
false);
279 stacked_widget& page = find_widget<stacked_widget>(&win,
"page",
false);
291 const int selected_row =
292 std::max(0, find_widget<listbox>(
get_window(),
"tabs",
false).get_selected_row());
293 find_widget<stacked_widget>(
get_window(),
"page",
false).select_layer(
static_cast<unsigned int>(selected_row));
295 if (selected_row == 3) {
315 std::stringstream
path;
317 if ((dlg.
path().find(images_dir) == std::string::npos)
318 && (dlg.
path().find(addons_dir) == std::string::npos)) {
323 if (id_stem ==
"unit_image") {
324 path << addons_dir +
"/units/" + filename;
325 }
else if ((id_stem ==
"portrait_image")||(id_stem ==
"small_profile_image")) {
326 path << addons_dir +
"/portraits/" + filename;
327 }
else if (id_stem ==
"attack_image") {
328 path << addons_dir +
"/attacks/" + filename;
336 if (
path.str().find(images_dir) != std::string::npos) {
338 path.str(
path.str().replace(0, images_dir.size()+1,
""));
339 }
else if (
path.str().find(addons_dir) != std::string::npos) {
341 path.str(
path.str().replace(0, addons_dir.size()+1,
""));
344 path.seekp(0, std::ios_base::end);
351 find_widget<text_box>(
get_window(),
"path_"+id_stem,
false).set_value(
path.str());
363 find_widget<text_box>(
get_window(),
"id_box",
false).set_value(
type->id());
364 find_widget<text_box>(
get_window(),
"name_box",
false).set_value(
type->type_name());
365 find_widget<spinner>(
get_window(),
"level_box",
false).set_value(
type->level());
366 find_widget<slider>(
get_window(),
"cost_slider",
false).set_value(
type->cost());
368 find_widget<slider>(
get_window(),
"hp_slider",
false).set_value(
type->hitpoints());
369 find_widget<slider>(
get_window(),
"xp_slider",
false).set_value(
type->experience_needed());
370 find_widget<slider>(
get_window(),
"move_slider",
false).set_value(
type->movement());
371 find_widget<scroll_text>(
get_window(),
"desc_box",
false).set_value(
type->unit_description());
373 find_widget<text_box>(
get_window(),
"path_unit_image",
false).set_value(
type->image());
374 find_widget<text_box>(
get_window(),
"path_portrait_image",
false).set_value(
type->big_profile());
376 for (
const auto& gender :
type->genders())
378 if (gender == unit_race::GENDER::MALE) {
379 find_widget<toggle_button>(
get_window(),
"gender_male",
false).set_value(
true);
382 if (gender == unit_race::GENDER::FEMALE) {
383 find_widget<toggle_button>(
get_window(),
"gender_female",
false).set_value(
true);
388 find_widget<menu_button>(
get_window(),
"race_list",
false),
393 find_widget<menu_button>(
get_window(),
"alignment_list",
false),
400 find_widget<text_box>(
get_window(),
"path_small_profile_image",
false).set_value(
type->small_profile());
403 find_widget<menu_button>(
get_window(),
"movetype_list",
false),
405 type->movement_type_id());
408 type->movement_type().write(cfg,
false);
415 if (!
type->get_cfg().has_child(
"resistance")) {
419 for (
const auto& attr :
type->get_cfg().mandatory_child(
"resistance").attribute_range()) {
427 if (
type->get_cfg().has_child(
"defense")) {
428 for (
const auto& attr :
type->get_cfg().mandatory_child(
"defense").attribute_range()) {
435 if (
type->get_cfg().has_child(
"movement_costs")) {
436 for (
const auto& attr :
type->get_cfg().mandatory_child(
"movement_costs").attribute_range()) {
449 find_widget<menu_button>(
get_window(),
"usage_list",
false),
457 for(
const auto& atk :
type->attacks())
461 attack[
"id"] = atk.id();
462 attack[
"name"] = atk.name();
463 attack[
"icon"] = atk.icon();
464 attack[
"range"] = atk.range();
465 attack[
"damage"] = atk.damage();
466 attack[
"number"] = atk.num_attacks();
467 attack[
"type"] = atk.type();
468 attacks_.push_back(std::make_pair(enabled, attack));
485 std::string current_textdomain =
"wesnoth-"+
addon_id_;
493 utype[
"id"] = find_widget<text_box>(
get_window(),
"id_box",
false).get_value();
494 utype[
"name"] =
t_string(find_widget<text_box>(
get_window(),
"name_box",
false).get_value(), current_textdomain);
495 utype[
"image"] = find_widget<text_box>(
get_window(),
"path_unit_image",
false).get_value();
496 utype[
"profile"] = find_widget<text_box>(
get_window(),
"path_portrait_image",
false).get_value();
497 utype[
"level"] = find_widget<spinner>(
get_window(),
"level_box",
false).get_value();
498 utype[
"advances_to"] = find_widget<text_box>(
get_window(),
"adv_box",
false).get_value();
499 utype[
"hitpoints"] = find_widget<slider>(
get_window(),
"hp_slider",
false).get_value();
500 utype[
"experience"] = find_widget<slider>(
get_window(),
"xp_slider",
false).get_value();
501 utype[
"cost"] = find_widget<slider>(
get_window(),
"cost_slider",
false).get_value();
502 utype[
"movement"] = find_widget<slider>(
get_window(),
"move_slider",
false).get_value();
503 utype[
"description"] =
t_string(find_widget<scroll_text>(
get_window(),
"desc_box",
false).get_value(), current_textdomain);
504 utype[
"race"] = find_widget<menu_button>(
get_window(),
"race_list",
false).get_value_string();
505 utype[
"alignment"] = find_widget<menu_button>(
get_window(),
"alignment_list",
false).get_value_string();
508 if (find_widget<toggle_button>(
get_window(),
"gender_male",
false).get_value()) {
509 if (find_widget<toggle_button>(
get_window(),
"gender_female",
false).get_value()) {
510 utype[
"gender"] =
"male,female";
512 utype[
"gender"] =
"male";
515 if (find_widget<toggle_button>(
get_window(),
"gender_female",
false).get_value()) {
516 utype[
"gender"] =
"female";
523 utype[
"small_profile"] = find_widget<text_box>(
get_window(),
"path_small_profile_image",
false).get_value();
524 utype[
"movement_type"] = find_widget<menu_button>(
get_window(),
"movetype_list",
false).get_value_string();
525 utype[
"usage"] = find_widget<menu_button>(
get_window(),
"usage_list",
false).get_value_string();
543 defenses[attr.first] =
defenses_[attr.first];
554 movement_costs[attr.first] =
movement_[attr.first];
560 const auto& abilities_states = find_widget<multimenu_button>(
get_window(),
"abilities_list",
false).get_toggle_states();
561 if (abilities_states.any()) {
565 if (
i >= abilities_states.size()) {
569 if (abilities_states[
i] ==
true) {
581 find_widget<slider>(
get_window(),
"resistances_slider",
false)
583 100 -
resistances_[find_widget<menu_button>(
get_window(),
"resistances_list",
false).get_value_string()]);
585 find_widget<slider>(
get_window(),
"resistances_slider",
false)
588 find_widget<toggle_button>(
get_window(),
"resistances_checkbox",
false)
594 = 100 - find_widget<slider>(
get_window(),
"resistances_slider",
false).get_value();
598 bool toggle = find_widget<toggle_button>(
get_window(),
"resistances_checkbox",
false).get_value();
600 find_widget<slider>(
get_window(),
"resistances_slider",
false).set_active(toggle);
604 find_widget<slider>(
get_window(),
"defense_slider",
false)
606 100 -
defenses_[find_widget<menu_button>(
get_window(),
"defense_list",
false).get_value_string()]);
608 find_widget<slider>(
get_window(),
"defense_slider",
false)
611 find_widget<toggle_button>(
get_window(),
"defense_checkbox",
false)
616 defenses_[find_widget<menu_button>(
get_window(),
"defense_list",
false).get_value_string()]
617 = 100 - find_widget<slider>(
get_window(),
"defense_slider",
false).get_value();
621 bool toggle = find_widget<toggle_button>(
get_window(),
"defense_checkbox",
false).get_value();
623 find_widget<slider>(
get_window(),
"defense_slider",
false).set_active(toggle);
627 find_widget<slider>(
get_window(),
"movement_costs_slider",
false)
629 movement_[find_widget<menu_button>(
get_window(),
"movement_costs_list",
false).get_value_string()]);
631 find_widget<slider>(
get_window(),
"movement_costs_slider",
false)
634 find_widget<toggle_button>(
get_window(),
"movement_costs_checkbox",
false)
639 movement_[find_widget<menu_button>(
get_window(),
"movement_costs_list",
false).get_value_string()]
640 = find_widget<slider>(
get_window(),
"movement_costs_slider",
false).get_value();
644 bool toggle = find_widget<toggle_button>(
get_window(),
"movement_costs_checkbox",
false).get_value();
646 find_widget<slider>(
get_window(),
"movement_costs_slider",
false).set_active(toggle);
659 attack[
"id"] = find_widget<text_box>(
get_window(),
"atk_id_box",
false).get_value();
660 attack[
"name"] = find_widget<text_box>(
get_window(),
"atk_name_box",
false).get_value();
661 attack[
"icon"] = find_widget<text_box>(
get_window(),
"path_attack_image",
false).get_value();
662 attack[
"type"] = find_widget<menu_button>(
get_window(),
"attack_type_list",
false).get_value_string();
663 attack[
"damage"] = find_widget<slider>(
get_window(),
"dmg_box",
false).get_value();
664 attack[
"number"] = find_widget<slider>(
get_window(),
"dmg_num_box",
false).get_value();
665 if (find_widget<toggle_button>(
get_window(),
"range_melee",
false).get_value()) {
666 attack[
"range"] =
"melee";
668 if (find_widget<toggle_button>(
get_window(),
"range_ranged",
false).get_value()) {
669 attack[
"range"] =
"ranged";
682 find_widget<text_box>(
get_window(),
"atk_id_box",
false).set_value(attack[
"id"]);
683 find_widget<text_box>(
get_window(),
"atk_name_box",
false).set_value(attack[
"name"]);
684 find_widget<text_box>(
get_window(),
"path_attack_image",
false).set_value(attack[
"icon"]);
686 find_widget<slider>(
get_window(),
"dmg_box",
false).set_value(attack[
"damage"]);
687 find_widget<slider>(
get_window(),
"dmg_num_box",
false).set_value(attack[
"number"]);
689 if (attack[
"range"] ==
"melee") {
690 find_widget<toggle_button>(
get_window(),
"range_melee",
false).set_value(
true);
691 find_widget<toggle_button>(
get_window(),
"range_ranged",
false).set_value(
false);
693 if (attack[
"range"] ==
"ranged") {
694 find_widget<toggle_button>(
get_window(),
"range_melee",
false).set_value(
false);
695 find_widget<toggle_button>(
get_window(),
"range_ranged",
false).set_value(
true);
707 find_widget<menu_button>(
get_window(),
"attack_type_list",
false),
712 find_widget<multimenu_button>(
get_window(),
"weapon_specials_list",
false)
719 find_widget<button>(
get_window(),
"atk_prev",
false).set_active(
false);
721 find_widget<button>(
get_window(),
"atk_prev",
false).set_active(
true);
725 find_widget<button>(
get_window(),
"atk_delete",
false).set_active(
true);
727 find_widget<button>(
get_window(),
"atk_delete",
false).set_active(
false);
731 find_widget<button>(
get_window(),
"atk_next",
false).set_active(
false);
733 find_widget<button>(
get_window(),
"atk_next",
false).set_active(
true);
737 std::vector<config> atk_name_list;
738 for(
const auto& atk_data :
attacks_) {
739 atk_name_list.emplace_back(
"label", atk_data.second[
"name"]);
748 find_widget<label>(
get_window(),
"atk_number",
false).set_label(new_index_str);
756 attack[
"id"] = find_widget<text_box>(
get_window(),
"atk_id_box",
false).get_value();
757 attack[
"name"] = find_widget<text_box>(
get_window(),
"atk_name_box",
false).get_value();
758 attack[
"icon"] = find_widget<text_box>(
get_window(),
"path_attack_image",
false).get_value();
759 attack[
"type"] = find_widget<menu_button>(
get_window(),
"attack_type_list",
false).get_value_string();
760 attack[
"damage"] = find_widget<slider>(
get_window(),
"dmg_box",
false).get_value();
761 attack[
"number"] = find_widget<slider>(
get_window(),
"dmg_num_box",
false).get_value();
762 if (find_widget<toggle_button>(
get_window(),
"range_melee",
false).get_value()) {
763 attack[
"range"] =
"melee";
765 if (find_widget<toggle_button>(
get_window(),
"range_ranged",
false).get_value()) {
766 attack[
"range"] =
"ranged";
773 find_widget<multimenu_button>(
get_window(),
"weapon_specials_list",
false).get_toggle_states()
788 find_widget<button>(
get_window(),
"atk_delete",
false).set_active(
false);
836 .mandatory_child(
"units")
837 .child_range(
"movetype")) {
838 if (
movetype[
"name"] == find_widget<menu_button>(
get_window(),
"movetype_list",
false).get_value_string()) {
858 out <<
"{" << macro_name <<
"}\n";
868 std::stringstream wml_stream;
870 std::string current_textdomain =
"wesnoth-"+
addon_id_;
874 <<
"# This file was generated using the scenario editor.\n"
905 for (
const auto& attr : atk.second.attribute_range()) {
906 if (!attr.second.empty()) {
911 if(atk.first.any()) {
984 std::string rel_path = find_widget<text_box>(
get_window(),
"path_"+id_stem,
false).get_value();
987 if (rel_path.find(
"~") != std::string::npos) {
988 rel_path = rel_path.substr(0, rel_path.find(
"~"));
993 std::stringstream mod_path(rel_path);
994 mod_path.seekp(0, std::ios_base::end);
997 mod_path <<
"~SCALE(" <<
size <<
"," <<
size <<
")";
1000 if (id_stem ==
"portrait_image") {
1002 find_widget<image>(
get_window(),
"unit_image",
false).set_label(mod_path.str());
1004 find_widget<image>(
get_window(), id_stem,
false).set_label(mod_path.str());
1013 if (!(std::isalnum(
c) ||
c ==
'_')) {
1022 std::string
id = find_widget<text_box>(
get_window(),
"id_box",
false).get_value();
1023 std::string name = find_widget<text_box>(
get_window(),
"name_box",
false).get_value();
1029 find_widget<button>(
get_window(),
"ok",
false).set_active(
false);
1031 find_widget<button>(
get_window(),
"ok",
false).set_active(
true);
1038 std::string
id = find_widget<text_box>(
get_window(),
"id_box",
false).get_value();
1039 find_widget<button>(
get_window(),
"ok",
false).set_active( !
id.empty() ||
check_id(
id) );
1049 boost::algorithm::replace_all(
unit_name,
" ",
"_");
1064 const SDL_Keycode key,
1065 SDL_Keymod modifier)
1069 const SDL_Keycode modifier_key = KMOD_GUI;
1073 const SDL_Keycode modifier_key = KMOD_CTRL;
1079 if (modifier & modifier_key) {
Class for writing a config out to a file in pieces.
void close_child(const std::string &key)
void open_child(const std::string &key)
A config object defines a single node in a WML file, with access to child nodes.
std::size_t attribute_count() const
Count the number of non-blank attributes.
config & mandatory_child(config_key_type key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
const_attr_itors attribute_range() const
config & add_child(config_key_type key)
A class grating read only view to a vector of config objects, viewed as one config with all children ...
const config & mandatory_child(config_key_type key) const
Dialog that allows user to create custom unit types.
unsigned int selected_attack_
0 means there are no attacks.
void write()
Write the cfg file.
bool check_id(std::string id)
Utility method to check if ID contains any invalid characters.
std::vector< config > defense_list_
boost::dynamic_bitset res_toggles_
Used to control checkboxes, so that only specific values are overridden.
const game_config_view & game_config_
std::vector< std::string > sel_abilities_
Need this because can't store macros in config.
std::vector< std::pair< boost::dynamic_bitset<>, config > > attacks_
std::vector< config > abilities_list_
void store_attack()
Callbacks for attack page.
void set_selected_from_string(menu_button &list, std::vector< config > values, std::string item)
Utility method to set state of menu_button from a string.
std::vector< config > movetype_list_
std::vector< config > race_list_
void update_defenses()
Callbacks for defense list.
std::string generated_wml
Generated WML.
void save_unit_type()
Save Unit Type data to cfg.
std::vector< config > align_list_
void button_state_change()
Callback to enable/disable OK button if ID/Name is invalid.
bool check_big(std::string img_abs_path, const int scale_size)
Check if width/height bigger than a specified size.
void signal_handler_sdl_key_down(const event::ui_event, bool &handled, const SDL_Keycode key, SDL_Keymod modifier)
editor_edit_unit(const game_config_view &game_config, const std::string &addon_id)
void select_file(const std::string &default_dir, const std::string &id_stem)
Callback for file select button.
void button_state_change_id()
preproc_map specials_map_
void write_macro(std::ostream &out, int level, std::string macro_name)
Write macro to a stream at specified tab level.
boost::dynamic_bitset move_toggles_
void update_movement_costs()
Callbacks for movement list.
std::vector< config > resistances_list_
preproc_map abilities_map_
void enable_defense_slider()
void on_page_select()
Callback when an tab item in the "page" listbox is selected.
void update_resistances()
Callback for resistance list.
const std::string & addon_id_
void store_movement_costs()
void enable_movement_slider()
std::vector< config > specials_list_
void enable_resistances_slider()
boost::dynamic_bitset def_toggles_
void load_unit_type()
Load Unit Type data from cfg.
void update_wml_view()
Update wml preview.
std::vector< config > usage_type_list_
virtual void pre_show(window &window) override
Actions to be taken before showing the window.
void load_movetype()
Callback for loading movetype data in UI.
void update_image(const std::string &id_stem)
Callback for image update.
file_dialog & set_ok_label(const std::string &value)
Sets the OK button label.
file_dialog & set_path(const std::string &value)
Sets the initial file selection.
file_dialog & set_title(const std::string &value)
Sets the current dialog title text.
file_dialog & set_read_only(bool value)
Whether to provide user interface elements for manipulating existing objects.
std::string path() const
Gets the current file selection.
Abstract base class for all modal dialogs.
bool show(const unsigned auto_close_time=0)
Shows the window.
window * get_window()
Returns a pointer to the dialog's window.
This shows the debug-mode dialog to create new units on the map.
const std::string & choice() const
Unit type choice from the user.
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.
bool select_row(const unsigned row, const bool select=true)
Selects a row.
base class of top level items, the only item which needs to store the final canvases to draw on.
void keyboard_capture(widget *widget)
void invalidate_layout()
Updates the size of the window.
static const std::string & type()
Static type getter that does not rely on the widget being constructed.
The basic "size" of the unit - flying, small land, large land, etc.
const movement_type_map & movement_types() const
const unit_type * find(const std::string &key, unit_type::BUILD_STATUS status=unit_type::FULL) const
Finds a unit_type by its id() and makes sure it is built to the specified level.
const race_map & races() const
A single unit type that the player may recruit.
Declarations for File-IO.
static std::string _(const char *str)
void copy_file(const std::string &src, const std::string &dest)
Read a file and then writes it back out.
std::string get_binary_file_location(const std::string &type, const std::string &filename)
Returns a complete path to the actual file of a given type or an empty string if the file isn't prese...
void write_file(const std::string &fname, const std::string &data, std::ios_base::openmode mode)
Throws io_exception if an error occurs.
std::string get_core_images_dir()
std::string get_current_editor_dir(const std::string &addon_id)
Game configuration data as global variables.
REGISTER_DIALOG(editor_edit_unit)
ui_event
The event sent to the dispatcher.
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::vector< game_tip > load(const config &cfg)
Loads the tips from a config.
std::string default_dir()
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
filesystem::scoped_istream preprocess_file(const std::string &fname, preproc_map *defines)
Function to use the WML preprocessor on a file.
static config unit_name(const unit *u)
void read(config &cfg, std::istream &in, abstract_validator *validator)
void write_key_val(std::ostream &out, const std::string &key, const config::attribute_value &value, unsigned level, std::string &textdomain)
An exception object used when an IO error occurs.
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
unit_type_data unit_types