wesnoth/src/editor/map/context_manager.cpp
2017-04-21 18:52:49 -04:00

1045 lines
28 KiB
C++

/*
Copyright (C) 2003 - 2017 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#define GETTEXT_DOMAIN "wesnoth-editor"
#include "resources.hpp"
#include "team.hpp"
#include "config_assign.hpp"
#include "display.hpp"
#include "editor/map/context_manager.hpp"
#include "editor/map/map_context.hpp"
#include "filesystem.hpp"
#include "formula/string_utils.hpp"
#include "game_board.hpp"
#include "generators/map_create.hpp"
#include "generators/map_generator.hpp"
#include "gettext.hpp"
#include "editor/action/action.hpp"
#include "editor/controller/editor_controller.hpp"
#include "editor/editor_preferences.hpp"
#include "gui/dialogs/edit_text.hpp"
#include "gui/dialogs/editor/generate_map.hpp"
#include "gui/dialogs/editor/new_map.hpp"
#include "gui/dialogs/editor/resize_map.hpp"
#include "gui/dialogs/file_dialog.hpp"
#include "gui/dialogs/message.hpp"
#include "gui/dialogs/transient_message.hpp"
#include "gui/widgets/window.hpp"
#include "gui/dialogs/editor/edit_scenario.hpp"
#include "gui/dialogs/editor/edit_side.hpp"
#include "terrain/translation.hpp"
#include <memory>
namespace editor {
static std::vector<std::string> saved_windows_;
static map_labels* current_labels;
map_labels* get_current_labels()
{
return current_labels;
}
/**
* Utility class to properly refresh the display when the map context object is replaced
* without duplicating code.
*/
class map_context_refresher
{
public:
map_context_refresher(context_manager& ec, const map_context& other_mc)
: context_manager_(ec)
, size_changed_(!ec.get_map().same_size_as(other_mc.get_map()))
, refreshed_(false)
{
}
~map_context_refresher()
{
if(!refreshed_) refresh();
}
void refresh()
{
context_manager_.gui().change_display_context(&context_manager_.get_map_context());
// TODO register the tod_manager with the gui?
resources::tod_manager = context_manager_.get_map_context().get_time_manager();
resources::units = &context_manager_.get_map_context().get_units();
resources::filter_con = &context_manager_.gui();
context_manager_.gui().replace_overlay_map(&context_manager_.get_map_context().get_overlays());
resources::classification = &context_manager_.get_map_context().get_classification();
context_manager_.gui().init_flags();
context_manager_.reload_map();
current_labels->enable(false);
current_labels = &context_manager_.get_map_context().get_labels();
current_labels->enable(true);
refreshed_ = true;
}
private:
context_manager& context_manager_;
bool size_changed_;
bool refreshed_;
};
context_manager::context_manager(editor_display& gui, const config& game_config)
: gui_(gui)
, game_config_(game_config)
, default_dir_(preferences::editor::default_dir())
, map_generators_()
, last_map_generator_(nullptr)
, current_context_index_(0)
, auto_update_transitions_(preferences::editor::auto_update_transitions())
, map_contexts_()
, clipboard_()
{
if(default_dir_.empty()) {
default_dir_ = filesystem::get_dir(filesystem::get_user_data_dir() + "/editor");
}
create_default_context();
init_map_generators(game_config);
}
context_manager::~context_manager()
{
for(map_generator* m : map_generators_) {
delete m;
}
// Restore default window title
CVideo::get_singleton().set_window_title(game_config::get_default_title_string());
}
void context_manager::refresh_all()
{
gui_.rebuild_all();
get_map_context().set_needs_terrain_rebuild(false);
gui_.create_buttons();
gui_.invalidate_all();
gui_.draw(false);
get_map_context().clear_changed_locations();
gui_.recalculate_minimap();
}
void context_manager::reload_map()
{
gui_.reload_map();
get_map_context().set_needs_reload(false);
get_map_context().reset_starting_position_labels(gui_);
refresh_all();
}
bool context_manager::is_active_transitions_hotkey(const std::string& item)
{
switch (auto_update_transitions_) {
case preferences::editor::TransitionUpdateMode::on:
return (item == "editor-auto-update-transitions");
case preferences::editor::TransitionUpdateMode::partial:
return (item == "editor-partial-update-transitions");
case preferences::editor::TransitionUpdateMode::off:
return (item == "editor-no-update-transitions");
}
return true; //should not be reached
}
bool context_manager::toggle_update_transitions()
{
auto_update_transitions_ = (auto_update_transitions_ + 1) % preferences::editor::TransitionUpdateMode::count;
preferences::editor::set_auto_update_transitions(auto_update_transitions_);
if(auto_update_transitions_ != preferences::editor::TransitionUpdateMode::on) {
return true;
}
return false;
}
size_t context_manager::modified_maps(std::string& message)
{
std::vector<std::string> modified;
for(auto& mc : map_contexts_) {
if(mc->modified()) {
if(!mc->get_filename().empty()) {
modified.push_back(mc->get_filename());
} else {
modified.push_back(_("(New Map)"));
}
}
}
for(std::string& str : modified) {
message += "\n" + font::unicode_bullet + " " + str;
}
return modified.size();
}
void context_manager::load_map_dialog(bool force_same_context /* = false */)
{
std::string fn = filesystem::directory_name(get_map_context().get_filename());
if(fn.empty()) {
fn = default_dir_;
}
gui2::dialogs::file_dialog dlg;
dlg.set_title(_("Load Map"))
.set_path(fn);
if(dlg.show(gui_.video())) {
load_map(dlg.path(), !force_same_context);
}
}
void context_manager::load_mru_item(unsigned int index, bool force_same_context /* = false */)
{
const std::vector<std::string>& mru = preferences::editor::recent_files();
if(mru.empty() || index >= mru.size()) {
return;
}
load_map(mru[index], !force_same_context);
}
void context_manager::edit_side_dialog(int side_index)
{
team& t = get_map_context().get_teams()[side_index];
//TODO
//t.support()
editor_team_info team_info(t);
// The side number perhaps should have been set in map_context::new_side() but the design of team::team_info appears to be read-only.
team_info.side = side_index + 1; // note team_info::side is supposed to be 1 to n, while side/team indexes are 0 to n-1
if(gui2::dialogs::editor_edit_side::execute(team_info, gui_.video())) {
get_map_context().set_side_setup(team_info);
}
}
void context_manager::edit_scenario_dialog()
{
map_context& context = get_map_context();
// TODO
//std::string fn = filesystem::directory_name(context.get_filename());
std::string id = context.get_id();
std::string name = context.get_name();
std::string description = context.get_description();
int turns = context.get_time_manager()->number_of_turns();
int xp_mod = context.get_xp_mod();
bool victory = context.victory_defeated();
bool random = context.random_start_time();
bool ok = gui2::dialogs::editor_edit_scenario::execute(
id, name, description, turns, xp_mod, victory, random, gui_.video()
);
if(ok) {
context.set_scenario_setup(id, name, description, turns, xp_mod, victory, random);
}
}
void context_manager::new_map_dialog()
{
int w = get_map().w();
int h = get_map().h();
if(gui2::dialogs::editor_new_map::execute(w, h, gui_.video())) {
const t_translation::terrain_code& fill = get_selected_bg_terrain();
new_map(w, h, fill, true);
}
}
void context_manager::new_scenario_dialog()
{
int w = get_map().w();
int h = get_map().h();
if(gui2::dialogs::editor_new_map::execute(w, h, gui_.video())) {
const t_translation::terrain_code& fill = get_selected_bg_terrain();
new_scenario(w, h, fill, true);
}
}
void context_manager::expand_open_maps_menu(std::vector<config>& items, int i)
{
auto pos = items.erase(items.begin() + i);
std::vector<config> contexts;
for(size_t mci = 0; mci < map_contexts_.size(); ++mci) {
std::string filename = map_contexts_[mci]->get_filename();
bool changed = map_contexts_[mci]->modified();
bool pure_map = map_contexts_[mci]->is_pure_map();
if(filename.empty()) {
if(pure_map) {
filename = _("(New Map)");
} else {
filename = _("(New Scenario)");
}
}
std::string label = "[" + std::to_string(mci) + "] "
+ filename + (changed ? " [*]" : "");
if(map_contexts_[mci]->is_embedded()) {
label += " (E)";
}
contexts.emplace_back(config_of("label", label));
}
items.insert(pos, contexts.begin(), contexts.end());
}
void context_manager::expand_load_mru_menu(std::vector<config>& items, int i)
{
std::vector<std::string> mru = preferences::editor::recent_files();
auto pos = items.erase(items.begin() + i);
if(mru.empty()) {
items.insert(pos, config_of("label", _("No Recent Files")));
return;
}
for(std::string& path : mru) {
// TODO: add proper leading ellipsization instead, since otherwise
// it'll be impossible to tell apart files with identical names and
// different parent paths.
path = filesystem::base_name(path);
}
std::vector<config> temp;
std::transform(mru.begin(), mru.end(), std::back_inserter(temp), [](const std::string& str) {
return config_of("label", str);
});
items.insert(pos, temp.begin(), temp.end());
}
void context_manager::expand_areas_menu(std::vector<config>& items, int i)
{
tod_manager* tod = get_map_context().get_time_manager();
if(!tod) {
return;
}
auto pos = items.erase(items.begin() + i);
std::vector<config> area_entries;
std::vector<std::string> area_ids = tod->get_area_ids();
for(size_t mci = 0; mci < area_ids.size(); ++mci) {
const std::string& area = area_ids[mci];
std::stringstream label;
label << "[" << mci + 1 << "] ";
label << (area.empty() ? _("(Unnamed Area)") : area);
if(mci == static_cast<size_t>(get_map_context().get_active_area())
&& tod->get_area_by_index(mci) != get_map_context().get_map().selection()) {
label << " [*]";
}
area_entries.emplace_back(config_of("label", label.str()));
}
items.insert(pos, area_entries.begin(), area_entries.end());
}
void context_manager::expand_sides_menu(std::vector<config>& items, int i)
{
auto pos = items.erase(items.begin() + i);
std::vector<config> contexts;
for(size_t mci = 0; mci < get_map_context().get_teams().size(); ++mci) {
const team& t = get_map_context().get_teams()[mci];
const std::string& teamname = t.user_team_name();
std::stringstream label;
label << "[" << mci+1 << "] ";
label << (teamname.empty() ? _("(New Side)") : teamname);
contexts.emplace_back(config_of("label", label.str()));
}
items.insert(pos, contexts.begin(), contexts.end());
}
void context_manager::expand_time_menu(std::vector<config>& items, int i)
{
auto pos = items.erase(items.begin() + i);
std::vector<config> times;
tod_manager* tod_m = get_map_context().get_time_manager();
assert(tod_m != nullptr);
for(const time_of_day& time : tod_m->times()) {
times.emplace_back(config_of
("details", time.name) // Use 'details' field here since the image will take the first column
("image", time.image)
);
}
items.insert(pos, times.begin(), times.end());
}
void context_manager::expand_local_time_menu(std::vector<config>& items, int i)
{
auto pos = items.erase(items.begin() + i);
std::vector<config> times;
tod_manager* tod_m = get_map_context().get_time_manager();
for(const time_of_day& time : tod_m->times(get_map_context().get_active_area())) {
times.emplace_back(config_of
("details", time.name) // Use 'details' field here since the image will take the first column
("image", time.image)
);
}
items.insert(pos, times.begin(), times.end());
}
void context_manager::apply_mask_dialog()
{
std::string fn = get_map_context().get_filename();
if(fn.empty()) {
fn = default_dir_;
}
gui2::dialogs::file_dialog dlg;
dlg.set_title(_("Apply Mask"))
.set_path(fn);
if(dlg.show(gui_.video())) {
try {
map_context mask(game_config_, dlg.path());
editor_action_apply_mask a(mask.get_map());
perform_refresh(a);
} catch (editor_map_load_exception& e) {
gui2::show_transient_message(gui_.video(), _("Error loading mask"), e.what());
return;
} catch (editor_action_exception& e) {
gui2::show_error_message(gui_.video(), e.what());
return;
}
}
}
void context_manager::perform_refresh(const editor_action& action, bool drag_part /* =false */)
{
get_map_context().perform_action(action);
refresh_after_action(drag_part);
}
void context_manager::rename_area_dialog()
{
int active_area = get_map_context().get_active_area();
std::string name = get_map_context().get_time_manager()->get_area_ids()[active_area];
if(gui2::dialogs::edit_text::execute(N_("Rename Area"), N_("Identifier:"), name, gui_.video())) {
get_map_context().get_time_manager()->set_area_id(active_area, name);
}
}
void context_manager::create_mask_to_dialog()
{
std::string fn = get_map_context().get_filename();
if(fn.empty()) {
fn = default_dir_;
}
gui2::dialogs::file_dialog dlg;
dlg.set_title(_("Choose Target Map"))
.set_path(fn);
if(dlg.show(gui_.video())) {
try {
map_context map(game_config_, dlg.path());
editor_action_create_mask a(map.get_map());
perform_refresh(a);
} catch (editor_map_load_exception& e) {
gui2::show_transient_message(gui_.video(), _("Error loading map"), e.what());
return;
} catch (editor_action_exception& e) {
gui2::show_error_message(gui_.video(), e.what());
return;
}
}
}
void context_manager::refresh_after_action(bool drag_part)
{
if(get_map_context().needs_reload()) {
reload_map();
return;
}
const std::set<map_location>& changed_locs = get_map_context().changed_locations();
if(get_map_context().needs_terrain_rebuild()) {
if((auto_update_transitions_ == preferences::editor::TransitionUpdateMode::on)
|| ((auto_update_transitions_ == preferences::editor::TransitionUpdateMode::partial)
&& (!drag_part || get_map_context().everything_changed())))
{
gui_.rebuild_all();
get_map_context().set_needs_terrain_rebuild(false);
gui_.invalidate_all();
} else {
for(const map_location& loc : changed_locs) {
gui_.rebuild_terrain(loc);
}
gui_.invalidate(changed_locs);
}
} else {
if(get_map_context().everything_changed()) {
gui_.invalidate_all();
} else {
gui_.invalidate(changed_locs);
}
}
if(get_map_context().needs_labels_reset()) {
get_map_context().reset_starting_position_labels(gui_);
}
get_map_context().clear_changed_locations();
gui_.recalculate_minimap();
}
void context_manager::resize_map_dialog()
{
int w = get_map().w();
int h = get_map().h();
gui2::dialogs::editor_resize_map::EXPAND_DIRECTION dir = gui2::dialogs::editor_resize_map::EXPAND_DIRECTION();
bool copy = false;
if(!gui2::dialogs::editor_resize_map::execute(w, h, dir, copy, gui_.video())) {
return;
}
if(w != get_map().w() || h != get_map().h()) {
t_translation::terrain_code fill = get_selected_bg_terrain();
if(copy) {
fill = t_translation::NONE_TERRAIN;
}
int x_offset = get_map().w() - w;
int y_offset = get_map().h() - h;
switch (dir) {
case gui2::dialogs::editor_resize_map::EXPAND_BOTTOM_RIGHT:
case gui2::dialogs::editor_resize_map::EXPAND_BOTTOM:
case gui2::dialogs::editor_resize_map::EXPAND_BOTTOM_LEFT:
y_offset = 0;
break;
case gui2::dialogs::editor_resize_map::EXPAND_RIGHT:
case gui2::dialogs::editor_resize_map::EXPAND_CENTER:
case gui2::dialogs::editor_resize_map::EXPAND_LEFT:
y_offset /= 2;
break;
case gui2::dialogs::editor_resize_map::EXPAND_TOP_RIGHT:
case gui2::dialogs::editor_resize_map::EXPAND_TOP:
case gui2::dialogs::editor_resize_map::EXPAND_TOP_LEFT:
break;
default:
y_offset = 0;
WRN_ED << "Unknown resize expand direction" << std::endl;
break;
}
switch (dir) {
case gui2::dialogs::editor_resize_map::EXPAND_BOTTOM_RIGHT:
case gui2::dialogs::editor_resize_map::EXPAND_RIGHT:
case gui2::dialogs::editor_resize_map::EXPAND_TOP_RIGHT:
x_offset = 0;
break;
case gui2::dialogs::editor_resize_map::EXPAND_BOTTOM:
case gui2::dialogs::editor_resize_map::EXPAND_CENTER:
case gui2::dialogs::editor_resize_map::EXPAND_TOP:
x_offset /= 2;
break;
case gui2::dialogs::editor_resize_map::EXPAND_BOTTOM_LEFT:
case gui2::dialogs::editor_resize_map::EXPAND_LEFT:
case gui2::dialogs::editor_resize_map::EXPAND_TOP_LEFT:
break;
default:
x_offset = 0;
break;
}
editor_action_resize_map a(w, h, x_offset, y_offset, fill);
perform_refresh(a);
}
}
void context_manager::save_map_as_dialog()
{
std::string input_name = get_map_context().get_filename();
if(input_name.empty()) {
input_name = filesystem::get_dir(default_dir_ + "/maps");
}
gui2::dialogs::file_dialog dlg;
dlg.set_title(_("Save Map As"))
.set_save_mode(true)
.set_path(input_name)
.set_extension(".map");
if(!dlg.show(gui_.video())) {
return;
}
save_map_as(dlg.path());
}
void context_manager::save_scenario_as_dialog()
{
std::string input_name = get_map_context().get_filename();
if(input_name.empty()) {
input_name = filesystem::get_dir(default_dir_ + "/scenarios");
}
gui2::dialogs::file_dialog dlg;
dlg.set_title(_("Save Scenario As"))
.set_save_mode(true)
.set_path(input_name)
.set_extension(".cfg");
if(!dlg.show(gui_.video())) {
return;
}
save_scenario_as(dlg.path());
}
void context_manager::init_map_generators(const config& game_config)
{
for(const config& i : game_config.child_range("multiplayer")) {
if(i["map_generation"].empty() && i["scenario_generation"].empty()) {
continue;
}
const config& generator_cfg = i.child("generator");
if(!generator_cfg) {
ERR_ED << "Scenario \"" << i["name"] << "\" with id " << i["id"]
<< " has map_generation= but no [generator] tag" << std::endl;
} else {
map_generator* m = create_map_generator(i["map_generation"], generator_cfg);
map_generators_.push_back(m);
}
}
}
void context_manager::generate_map_dialog()
{
if(map_generators_.empty()) {
gui2::show_error_message(gui_.video(), _("No random map generators found."));
return;
}
gui2::dialogs::editor_generate_map dialog;
dialog.set_map_generators(map_generators_);
dialog.select_map_generator(last_map_generator_);
dialog.show(gui_.video());
if(dialog.get_retval() == gui2::window::OK) {
std::string map_string;
map_generator* const map_generator = dialog.get_selected_map_generator();
try {
map_string = map_generator->create_map(dialog.get_seed());
} catch (mapgen_exception& e) {
gui2::show_transient_message(gui_.video(), _("Map creation failed."), e.what());
return;
}
if(map_string.empty()) {
gui2::show_transient_message(gui_.video(), "", _("Map creation failed."));
} else {
editor_map new_map(game_config_, map_string);
editor_action_whole_map a(new_map);
get_map_context().set_needs_labels_reset(); // Ensure Player Start labels are updated together with newly generated map
perform_refresh(a);
}
last_map_generator_ = map_generator;
}
}
bool context_manager::confirm_discard()
{
if(get_map_context().modified()) {
const int res = gui2::show_message(gui_.video(), _("Unsaved Changes"),
_("Do you want to discard all changes made to the map since the last save?"), gui2::dialogs::message::yes_no_buttons);
return gui2::window::CANCEL != res;
}
return true;
}
void context_manager::fill_selection()
{
perform_refresh(editor_action_paint_area(get_map().selection(), get_selected_bg_terrain()));
}
void context_manager::save_all_maps(bool auto_save_windows)
{
int current = current_context_index_;
saved_windows_.clear();
for(size_t i = 0; i < map_contexts_.size(); ++i) {
switch_context(i);
std::string name = get_map_context().get_filename();
if(auto_save_windows) {
if(name.empty() || filesystem::is_directory(name)) {
std::ostringstream s;
s << default_dir_ << "/" << "window_" << i;
name = s.str();
get_map_context().set_filename(name);
}
}
saved_windows_.push_back(name);
save_map();
}
switch_context(current);
}
void context_manager::save_map()
{
const std::string& name = get_map_context().get_filename();
if(name.empty() || filesystem::is_directory(name)) {
if(get_map_context().is_pure_map()) {
save_map_as_dialog();
} else {
save_scenario_as_dialog();
}
} else {
if(get_map_context().is_pure_map()) {
write_map();
} else {
write_scenario();
}
}
}
bool context_manager::save_scenario_as(const std::string& filename)
{
size_t is_open = check_open_map(filename);
if(is_open < map_contexts_.size() && is_open != static_cast<unsigned>(current_context_index_)) {
gui2::show_transient_message(gui_.video(), _("This scenario is already open."), filename);
return false;
}
std::string old_filename = get_map_context().get_filename();
bool embedded = get_map_context().is_embedded();
get_map_context().set_filename(filename);
get_map_context().set_embedded(false);
if(!write_scenario(true)) {
get_map_context().set_filename(old_filename);
get_map_context().set_embedded(embedded);
return false;
}
return true;
}
bool context_manager::save_map_as(const std::string& filename)
{
size_t is_open = check_open_map(filename);
if(is_open < map_contexts_.size() && is_open != static_cast<unsigned>(current_context_index_)) {
gui2::show_transient_message(gui_.video(), _("This map is already open."), filename);
return false;
}
std::string old_filename = get_map_context().get_filename();
bool embedded = get_map_context().is_embedded();
get_map_context().set_filename(filename);
get_map_context().set_embedded(false);
if(!write_map(true)) {
get_map_context().set_filename(old_filename);
get_map_context().set_embedded(embedded);
return false;
}
return true;
}
bool context_manager::write_scenario(bool display_confirmation)
{
try {
get_map_context().save_scenario();
if(display_confirmation) {
gui2::show_transient_message(gui_.video(), "", _("Scenario saved."));
}
} catch (editor_map_save_exception& e) {
gui2::show_transient_message(gui_.video(), "", e.what());
return false;
}
return true;
}
bool context_manager::write_map(bool display_confirmation)
{
try {
get_map_context().save_map();
if(display_confirmation) {
gui2::show_transient_message(gui_.video(), "", _("Map saved."));
}
} catch (editor_map_save_exception& e) {
gui2::show_transient_message(gui_.video(), "", e.what());
return false;
}
return true;
}
size_t context_manager::check_open_map(const std::string& fn) const
{
size_t i = 0;
while(i < map_contexts_.size() && map_contexts_[i]->get_filename() != fn) {
++i;
}
return i;
}
bool context_manager::check_switch_open_map(const std::string& fn)
{
size_t i = check_open_map(fn);
if(i < map_contexts_.size()) {
gui2::show_transient_message(gui_.video(), _("This map is already open."), fn);
switch_context(i);
return true;
}
return false;
}
void context_manager::load_map(const std::string& filename, bool new_context)
{
if(new_context && check_switch_open_map(filename)) {
return;
}
LOG_ED << "Load map: " << filename << (new_context ? " (new)" : " (same)") << "\n";
try {
{
context_ptr mc(new map_context(game_config_, filename));
if(mc->get_filename() != filename) {
if(new_context && check_switch_open_map(mc->get_filename())) {
return;
}
}
if(new_context) {
int new_id = add_map_context_of(std::move(mc));
switch_context(new_id);
} else {
replace_map_context_with(std::move(mc));
}
}
if(get_map_context().is_embedded()) {
const std::string& msg = _("Loaded embedded map data");
gui2::show_transient_message(gui_.video(), _("Map loaded from scenario"), msg);
} else {
if(get_map_context().get_filename() != filename) {
if(get_map_context().get_map_data_key().empty()) {
ERR_ED << "Internal error, map context filename changed: "
<< filename << " -> " << get_map_context().get_filename()
<< " with no apparent scenario load\n";
} else {
utils::string_map symbols;
symbols["old"] = filename;
const std::string& msg = _("Loaded referenced map file:\n$new");
symbols["new"] = get_map_context().get_filename();
symbols["map_data"] = get_map_context().get_map_data_key();
gui2::show_transient_message(gui_.video(), _("Map loaded from scenario"),
//TODO: msg is already translated does vgettext make sense?
vgettext(msg.c_str(), symbols));
}
}
}
} catch (editor_map_load_exception& e) {
gui2::show_transient_message(gui_.video(), _("Error loading map"), e.what());
return;
}
}
void context_manager::revert_map()
{
if(!confirm_discard()) {
return;
}
std::string filename = get_map_context().get_filename();
if(filename.empty()) {
ERR_ED << "Empty filename in map revert" << std::endl;
return;
}
load_map(filename, false);
}
void context_manager::new_map(int width, int height, const t_translation::terrain_code& fill, bool new_context)
{
const config& default_schedule = game_config_.find_child("editor_times", "id", "default");
editor_map m(game_config_, width, height, fill);
if(new_context) {
int new_id = add_map_context(m, true, default_schedule);
switch_context(new_id);
} else {
replace_map_context(m, true, default_schedule);
}
}
void context_manager::new_scenario(int width, int height, const t_translation::terrain_code& fill, bool new_context)
{
const config& default_schedule = game_config_.find_child("editor_times", "id", "default");
editor_map m(game_config_, width, height, fill);
if(new_context) {
int new_id = add_map_context(m, false, default_schedule);
switch_context(new_id);
} else {
replace_map_context(m, false, default_schedule);
}
}
//
// Context manipulation
//
template<typename... T>
int context_manager::add_map_context(const T&... args)
{
map_contexts_.emplace_back(new map_context(args...));
return map_contexts_.size() - 1;
}
int context_manager::add_map_context_of(context_ptr&& mc)
{
map_contexts_.emplace_back(std::move(mc));
return map_contexts_.size() - 1;
}
template<typename... T>
void context_manager::replace_map_context(const T&... args)
{
context_ptr new_mc(new map_context(args...));
replace_map_context_with(std::move(new_mc));
}
void context_manager::replace_map_context_with(context_ptr&& mc)
{
map_context_refresher mcr(*this, *mc);
map_contexts_[current_context_index_].swap(mc);
set_window_title();
}
void context_manager::create_default_context()
{
if(saved_windows_.empty()) {
t_translation::terrain_code default_terrain =
t_translation::read_terrain_code(game_config::default_terrain);
const config& default_schedule = game_config_.find_child("editor_times", "id", "default");
add_map_context(editor_map(game_config_, 44, 33, default_terrain), true, default_schedule);
} else {
for(const std::string& filename : saved_windows_) {
add_map_context(game_config_, filename);
}
saved_windows_.clear();
}
}
void context_manager::close_current_context()
{
if(!confirm_discard()) return;
map_context_refresher(*this, get_map_context());
if(map_contexts_.size() == 1) {
create_default_context();
map_contexts_.erase(map_contexts_.begin());
} else if(current_context_index_ == static_cast<int>(map_contexts_.size()) - 1) {
map_contexts_.pop_back();
current_context_index_--;
} else {
map_contexts_.erase(map_contexts_.begin() + current_context_index_);
}
set_window_title();
}
void context_manager::switch_context(const int index, const bool force)
{
if(index < 0 || static_cast<size_t>(index) >= map_contexts_.size()) {
WRN_ED << "Invalid index in switch map context: " << index << std::endl;
return;
}
if(index == current_context_index_ && !force) {
return;
}
map_context_refresher mcr(*this, *map_contexts_[index]);
current_labels = &get_map_context().get_labels();
current_context_index_ = index;
set_window_title();
}
void context_manager::set_window_title()
{
std::string map_name = filesystem::base_name(get_map_context().get_filename());
if(map_name.empty()){
map_name = get_map_context().is_pure_map() ? _("New Map") : _("New Scenario");
}
const std::string& wm_title_string = map_name + " - " + game_config::get_default_title_string();
CVideo::get_singleton().set_window_title(wm_title_string);
}
} //Namespace editor