16 #define GETTEXT_DOMAIN "wesnoth-editor"
59 std::ostringstream ss;
63 ss <<
"color='#f00' ";
76 , last_map_generator_(nullptr)
77 , current_context_index_(0)
109 if (
gui().get_teams().
size() > 0) {
132 for(
const auto& loc :
get_map_context().map().special_locations().left) {
139 for(
size_t i = 10;
i <= n_teams;
i++) {
158 return (
item ==
"editor-auto-update-transitions");
160 return (
item ==
"editor-partial-update-transitions");
162 return (
item ==
"editor-no-update-transitions");
182 std::vector<std::string> modified;
185 if(!mc->get_name().empty()) {
186 modified.push_back(mc->get_name());
187 }
else if(!mc->get_filename().empty()) {
188 modified.push_back(mc->get_filename());
190 modified.push_back(mc->get_default_context_name());
195 for(std::string& str : modified) {
199 return modified.size();
222 if(mru.empty() ||
index >= mru.size()) {
235 if(gui2::dialogs::editor_edit_side::execute(team_info)) {
247 std::string
id = context.
get_id();
248 std::string name = context.
get_name();
257 const bool ok = gui2::dialogs::editor_edit_scenario::execute(
258 id, name, description,
turns, xp_mod, victory, random
279 if(gui2::dialogs::editor_new_map::execute(
_(
"New Map"),
w,
h)) {
292 if(gui2::dialogs::editor_new_map::execute(
_(
"New Scenario"),
w,
h)) {
301 std::vector<config> contexts;
303 for(std::size_t mci = 0; mci <
map_contexts_.size(); ++mci) {
306 std::string filename;
313 if(filename.empty()) {
317 std::ostringstream ss;
318 ss <<
"[" << mci + 1 <<
"] ";
323 ss <<
"<i>" << filename <<
"</i>";
332 const std::string
label = ss.str();
335 contexts.emplace_back(
"label",
label,
"details", details);
338 items.insert(pos, contexts.begin(), contexts.end());
348 items.insert(pos,
config {
"label",
_(
"No Recent Files")});
352 for(std::string&
path : mru) {
359 std::vector<config> temp;
360 std::transform(mru.begin(), mru.end(), std::back_inserter(temp), [](
const std::string& str) {
361 return config {
"label", str};
364 items.insert(pos, temp.begin(), temp.end());
367 void context_manager::expand_areas_menu(std::vector<config>&
items,
int i)
369 tod_manager* tod = get_map_context().get_time_manager();
375 std::vector<config> area_entries;
377 std::vector<std::string> area_ids = tod->
get_area_ids();
379 for(std::size_t mci = 0; mci < area_ids.size(); ++mci) {
380 const std::string& area = area_ids[mci];
382 std::stringstream ss;
383 ss <<
"[" << mci + 1 <<
"] ";\
386 ss <<
"<i>" <<
_(
"Unnamed Area") <<
"</i>";
392 mci ==
static_cast<std::size_t
>(get_map_context().get_active_area())
395 const std::string
label = ss.str();
398 area_entries.emplace_back(
"label",
label,
"details", details);
401 items.insert(pos, area_entries.begin(), area_entries.end());
404 void context_manager::expand_sides_menu(std::vector<config>&
items,
int i)
407 std::vector<config> contexts;
409 for(std::size_t mci = 0; mci < get_map_context().teams().size(); ++mci) {
411 const team&
t = get_map_context().teams()[mci];
412 const std::string& teamname =
t.user_team_name();
413 std::stringstream
label;
414 label <<
"[" << mci+1 <<
"] ";
416 if(teamname.empty()) {
417 label <<
"<i>" <<
_(
"New Side") <<
"</i>";
422 contexts.emplace_back(
"label",
label.str());
425 items.insert(pos, contexts.begin(), contexts.end());
428 void context_manager::expand_time_menu(std::vector<config>&
items,
int i)
431 std::vector<config> times;
433 tod_manager* tod_m = get_map_context().get_time_manager();
435 assert(tod_m !=
nullptr);
439 "details", time.name,
444 items.insert(pos, times.begin(), times.end());
447 void context_manager::expand_local_time_menu(std::vector<config>&
items,
int i)
450 std::vector<config> times;
452 tod_manager* tod_m = get_map_context().get_time_manager();
454 for(
const time_of_day& time : tod_m->
times(get_map_context().get_active_area())) {
456 "details", time.name,
461 items.insert(pos, times.begin(), times.end());
464 void context_manager::apply_mask_dialog()
466 std::string fn = get_map_context().get_filename();
491 void context_manager::perform_refresh(
const editor_action& action,
bool drag_part )
493 get_map_context().perform_action(action);
494 refresh_after_action(drag_part);
497 void context_manager::rename_area_dialog()
499 int active_area = get_map_context().get_active_area();
500 std::string name = get_map_context().get_time_manager()->get_area_ids()[active_area];
502 if(gui2::dialogs::edit_text::execute(
N_(
"Rename Area"),
N_(
"Identifier:"), name)) {
503 get_map_context().get_time_manager()->set_area_id(active_area, name);
507 void context_manager::create_mask_to_dialog()
509 std::string fn = get_map_context().get_filename();
534 void context_manager::refresh_after_action(
bool drag_part)
536 if(get_map_context().needs_reload()) {
541 const std::set<map_location>& changed_locs = get_map_context().changed_locations();
543 if(get_map_context().needs_terrain_rebuild()) {
546 && (!drag_part || get_map_context().everything_changed())))
549 get_map_context().set_needs_terrain_rebuild(
false);
550 gui_.invalidate_all();
553 gui_.rebuild_terrain(loc);
555 gui_.invalidate(changed_locs);
558 if(get_map_context().everything_changed()) {
559 gui_.invalidate_all();
561 gui_.invalidate(changed_locs);
565 if(get_map_context().needs_labels_reset()) {
566 get_map_context().reset_starting_position_labels(gui_);
569 get_map_context().clear_changed_locations();
570 gui_.recalculate_minimap();
573 void context_manager::resize_map_dialog()
575 const editor_map& map = get_map_context().map();
583 if(!gui2::dialogs::editor_resize_map::execute(
w,
h, dir, copy)) {
587 if(
w != map.
w() ||
h != map.
h()) {
593 int x_offset = map.
w() -
w;
594 int y_offset = map.
h() -
h;
613 WRN_ED <<
"Unknown resize expand direction";
642 void context_manager::save_map_as_dialog()
644 std::string input_name = get_map_context().get_filename();
645 if(input_name.empty()) {
660 save_map_as(dlg.
path());
663 void context_manager::save_scenario_as_dialog()
665 std::string input_name = get_map_context().get_filename();
666 if(input_name.empty()) {
681 save_scenario_as(dlg.
path());
687 if(
i[
"map_generation"].empty() &&
i[
"scenario_generation"].empty()) {
692 if(
const auto generator_cfg =
i.optional_child(
"generator")) {
693 map_generators_.emplace_back(
create_map_generator(
i[
"map_generation"].empty() ?
i[
"scenario_generation"] :
i[
"map_generation"], generator_cfg.value()));
695 ERR_ED <<
"Scenario \"" <<
i[
"name"] <<
"\" with id " <<
i[
"id"]
696 <<
" has map_generation= but no [generator] tag";
701 void context_manager::generate_map_dialog()
703 if(map_generators_.empty()) {
712 std::string map_string;
721 if(map_string.empty()) {
726 get_map_context().set_needs_labels_reset();
734 bool context_manager::confirm_discard()
736 if(get_map_context().modified()) {
745 void context_manager::fill_selection()
750 void context_manager::save_all_maps(
bool auto_save_windows)
752 int current = current_context_index_;
754 for(std::size_t
i = 0;
i < map_contexts_.size(); ++
i) {
756 std::string name = get_map_context().get_filename();
757 if(auto_save_windows) {
759 std::ostringstream
s;
760 s << default_dir_ <<
"/" <<
"window_" <<
i + 1;
762 get_map_context().set_filename(name);
769 switch_context(current);
772 void context_manager::save_map()
774 const std::string& name = get_map_context().get_filename();
776 if(get_map_context().is_pure_map()) {
777 save_map_as_dialog();
779 save_scenario_as_dialog();
782 if(get_map_context().is_pure_map()) {
790 bool context_manager::save_scenario_as(
const std::string& filename)
792 std::size_t is_open = check_open_map(filename);
793 if(is_open < map_contexts_.size() && is_open !=
static_cast<unsigned>(current_context_index_)) {
798 std::string old_filename = get_map_context().get_filename();
799 bool embedded = get_map_context().is_embedded();
801 get_map_context().set_filename(filename);
802 get_map_context().set_embedded(
false);
804 if(!write_scenario(
true)) {
805 get_map_context().set_filename(old_filename);
806 get_map_context().set_embedded(embedded);
813 bool context_manager::save_map_as(
const std::string& filename)
815 std::size_t is_open = check_open_map(filename);
816 if(is_open < map_contexts_.size() && is_open !=
static_cast<unsigned>(current_context_index_)) {
821 std::string old_filename = get_map_context().get_filename();
822 bool embedded = get_map_context().is_embedded();
824 get_map_context().set_filename(filename);
825 get_map_context().set_embedded(
false);
827 if(!write_map(
true)) {
828 get_map_context().set_filename(old_filename);
829 get_map_context().set_embedded(embedded);
836 bool context_manager::write_scenario(
bool display_confirmation)
839 get_map_context().save_scenario();
840 if(display_confirmation) {
851 bool context_manager::write_map(
bool display_confirmation)
854 get_map_context().save_map();
855 if(display_confirmation) {
866 std::size_t context_manager::check_open_map(
const std::string& fn)
const
869 while(
i < map_contexts_.size() && map_contexts_[
i]->get_filename() != fn) {
876 bool context_manager::check_switch_open_map(
const std::string& fn)
878 std::size_t
i = check_open_map(fn);
879 if(
i < map_contexts_.size()) {
888 void context_manager::load_map(
const std::string& filename,
bool new_context)
890 if(new_context && check_switch_open_map(filename)) {
894 LOG_ED <<
"Load map: " << filename << (new_context ?
" (new)" :
" (same)");
898 if(mc->get_filename() != filename) {
899 if(new_context && check_switch_open_map(mc->get_filename())) {
905 int new_id = add_map_context_of(std::move(mc));
906 switch_context(new_id);
908 replace_map_context_with(std::move(mc));
912 if(get_map_context().is_embedded()) {
913 const std::string&
msg =
_(
"Loaded embedded map data");
917 if(get_map_context().get_map_data_key().empty()) {
918 ERR_ED <<
"Internal error, map context filename changed: "
919 << filename <<
" -> " << get_map_context().get_filename()
920 <<
" with no apparent scenario load";
923 symbols[
"old"] = filename;
924 const std::string&
msg =
_(
"Loaded referenced map file:\n$new");
925 symbols[
"new"] = get_map_context().get_filename();
926 symbols[
"map_data"] = get_map_context().get_map_data_key();
939 void context_manager::revert_map()
941 if(!confirm_discard()) {
945 std::string filename = get_map_context().get_filename();
946 if(filename.empty()) {
947 ERR_ED <<
"Empty filename in map revert";
951 load_map(filename,
false);
960 int new_id = add_map_context(m,
true, default_schedule);
961 switch_context(new_id);
963 replace_map_context(m,
true, default_schedule);
969 auto default_schedule = game_config_.find_child(
"editor_times",
"id",
"empty");
973 int new_id = add_map_context(m,
false, *default_schedule);
974 switch_context(new_id);
976 replace_map_context(m,
false, *default_schedule);
980 get_map_context().new_side();
981 gui().set_team(0,
true);
982 gui().set_playing_team(0);
990 template<
typename... T>
991 int context_manager::add_map_context(
const T&... args)
993 map_contexts_.emplace_back(
new map_context(args...));
994 return map_contexts_.size() - 1;
999 map_contexts_.emplace_back(std::move(mc));
1000 return map_contexts_.size() - 1;
1003 template<
typename... T>
1004 void context_manager::replace_map_context(
const T&... args)
1007 replace_map_context_with(std::move(new_mc));
1012 map_contexts_[current_context_index_].swap(mc);
1013 refresh_on_context_change();
1016 void context_manager::create_default_context()
1026 add_map_context(game_config_, filename);
1033 void context_manager::close_current_context()
1035 if(!confirm_discard())
return;
1037 if(map_contexts_.size() == 1) {
1038 create_default_context();
1039 map_contexts_.erase(map_contexts_.begin());
1040 }
else if(current_context_index_ ==
static_cast<int>(map_contexts_.size()) - 1) {
1041 map_contexts_.pop_back();
1042 current_context_index_--;
1044 map_contexts_.erase(map_contexts_.begin() + current_context_index_);
1047 refresh_on_context_change();
1050 void context_manager::switch_context(
const int index,
const bool force)
1052 if(
index < 0 ||
static_cast<std::size_t
>(
index) >= map_contexts_.size()) {
1053 WRN_ED <<
"Invalid index in switch map context: " <<
index;
1057 if(
index == current_context_index_ && !force) {
1063 get_map_context().get_labels().enable(
false);
1065 current_context_index_ =
index;
1067 refresh_on_context_change();
1072 std::string name = get_map_context().get_name();
1079 name = get_map_context().get_default_context_name();
A config object defines a single node in a WML file, with access to child nodes.
config & find_mandatory_child(config_key_type key, const std::string &name, const std::string &value)
void recalculate_minimap()
Schedule the minimap for recalculation.
void rebuild_all()
Rebuild all dynamic terrain.
void change_display_context(const display_context *dc)
void set_team(std::size_t team, bool observe=false)
Sets the team controlled by the player using the computer.
void invalidate_all()
Function to invalidate all tiles.
void init_flags()
Init the flag list and the team colors used by ~TC.
void reload_map()
Updates internals that cache map size.
void set_playing_team(std::size_t team)
set_playing_team sets the team whose turn it currently is
bool is_active_transitions_hotkey(const std::string &item)
void new_scenario(int width, int height, const t_translation::terrain_code &fill, bool new_context)
Create a new scenario.
void new_map(int width, int height, const t_translation::terrain_code &fill, bool new_context)
Create a new map.
context_manager(editor_display &gui, const game_config_view &game_config)
void new_map_dialog()
Display a new map dialog and process user input.
int auto_update_transitions_
Flag to rebuild terrain on every terrain change.
void load_map_dialog(bool force_same_context=false)
Display a load map dialog and process user input.
void set_window_title()
Displays the specified map name in the window titlebar.
void refresh_all()
Refresh everything, i.e.
void init_map_generators(const game_config_view &game_config)
init available random map generators
bool toggle_update_transitions()
void create_default_context()
Creates a default map context object, used to ensure there is always at least one.
void new_scenario_dialog()
Display a new map dialog and process user input.
void load_map(const std::string &filename, bool new_context)
Load a map given the filename.
void reload_map()
Reload the map after it has significantly changed (when e.g.
void edit_scenario_dialog()
Display a scenario edit dialog and process user input.
std::string default_dir_
Default directory for map load/save as dialogs.
std::unique_ptr< map_context > context_ptr
void load_mru_item(unsigned index, bool force_same_context=false)
Open the specified entry from the recent files list.
map_context & get_map_context()
Get the current map context object.
class location_palette * locs_
void expand_load_mru_menu(std::vector< config > &items, int i)
Menu expanding for most recent loaded list.
void expand_open_maps_menu(std::vector< config > &items, int i)
Menu expanding for open maps list.
std::vector< context_ptr > map_contexts_
The currently opened map context object.
void edit_side_dialog(int side_index)
Display a side edit dialog and process user input.
void refresh_on_context_change()
Performs the necessary housekeeping necessary when switching contexts.
std::size_t modified_maps(std::string &modified)
Paint the same terrain on a number of locations on the map.
Replace contents of the entire map, Useful as a fallback undo method when something else would be imp...
Base class for all editor actions.
This class adds extra editor-specific functionality to a normal gamemap.
void add_item(const std::string &id)
This class wraps around a map to provide a concise interface for the editor to work with.
void set_needs_reload(bool value=true)
Setter for the reload flag.
const std::string & get_id() const
bool random_start_time() const
void set_side_setup(editor_team_info &info)
TODO.
const std::string & get_description() const
void clear_changed_locations()
const tod_manager * get_time_manager() const
std::optional< int > get_xp_mod() const
void reset_starting_position_labels(display &disp)
virtual const editor_map & map() const override
Const map accessor.
void set_needs_terrain_rebuild(bool value=true)
Setter for the terrain rebuild flag.
const t_string get_default_context_name() const
const std::string & get_filename() const
map_labels & get_labels()
virtual const std::vector< team > & teams() const override
Const teams accessor.
game_classification & get_classification()
bool victory_defeated() const
void set_scenario_setup(const std::string &id, const std::string &name, const std::string &description, int turns, int xp_mod, bool victory_defeated, bool random_time)
TODO.
const std::string & get_name() const
A class grating read only view to a vector of config objects, viewed as one config with all children ...
int w() const
Effective map width.
int h() const
Effective map height.
The dialog for selecting which random generator to use in the editor.
std::optional< uint32_t > get_seed()
void select_map_generator(map_generator *mg)
map_generator * get_selected_map_generator()
file_dialog & set_extension(const std::string &value)
Sets the default file extension for file names in save mode.
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_save_mode(bool value)
Sets the dialog's behavior on non-existent file name inputs.
std::string path() const
Gets the current file selection.
@ yes_no_buttons
Shows a yes and no button.
bool show(const unsigned auto_close_time=0)
Shows the window.
virtual std::string create_map(std::optional< uint32_t > randomseed={})=0
Creates a new map and returns it.
void enable(bool is_enabled)
This class stores all the data for a single 'side' (in game nomenclature).
int number_of_turns() const
const std::vector< time_of_day > & times(const map_location &loc=map_location::null_location()) const
std::vector< std::string > get_area_ids() const
const std::set< map_location > & get_area_by_index(int index) const
Declarations for File-IO.
static std::string _(const char *str)
std::string label
What to show in the filter's drop-down list.
map_generator * create_map_generator(const std::string &name, const config &cfg, const config *vars)
void fill(const SDL_Rect &rect, uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Fill an area with the given colour.
Manage the empty-palette in the editor.
static const std::string get_menu_marker(const bool changed)
const t_translation::terrain_code & get_selected_bg_terrain()
static std::vector< std::string > saved_windows_
static bfs::path get_dir(const bfs::path &dirpath)
std::string get_user_data_dir()
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
const std::string unicode_bullet
Game configuration data as global variables.
std::string get_default_title_string()
std::string default_terrain
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_error_message(const std::string &msg, bool message_use_markup)
Shows an error 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.
@ CANCEL
Dialog was closed with the CANCEL button.
std::pair< std::string, unsigned > item
const std::vector< std::string > items
std::string default_dir()
void set_auto_update_transitions(int value)
int auto_update_transitions()
std::vector< std::string > recent_files()
Retrieves the list of recently opened files.
@ TRANSITION_UPDATE_PARTIAL
@ TRANSITION_UPDATE_COUNT
Modify, read and display user preferences.
::tod_manager * tod_manager
game_classification * classification
filter_context * filter_con
terrain_code read_terrain_code(std::string_view str, const ter_layer filler)
Reads a single terrain from a string.
const terrain_code NONE_TERRAIN
std::size_t index(const std::string &str, const std::size_t index)
Codepoint index corresponding to the nth character in a UTF-8 string.
std::map< std::string, t_string > string_map
void set_window_title(const std::string &title)
Sets the title of the main window.
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
static std::string get_filename(const std::string &file_code)
Encapsulates the map of the game.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Object which defines a time of day with associated bonuses, image, sounds etc.
static map_location::DIRECTION s