The Battle for Wesnoth  1.15.0-dev
context_manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 #define GETTEXT_DOMAIN "wesnoth-editor"
15 
16 #include "resources.hpp"
17 #include "team.hpp"
18 
19 #include "display.hpp"
22 #include "filesystem.hpp"
23 #include "formula/string_utils.hpp"
24 #include "game_board.hpp"
27 #include "gettext.hpp"
28 
29 #include "editor/action/action.hpp"
31 #include "preferences/editor.hpp"
32 
38 #include "gui/dialogs/message.hpp"
40 #include "gui/widgets/retval.hpp"
41 
44 
45 #include "terrain/translation.hpp"
46 
47 #include <memory>
48 
49 namespace editor {
50 
51 static std::vector<std::string> saved_windows_;
52 
53 static const std::string get_menu_marker(const bool changed)
54 {
55  std::ostringstream ss;
56  ss << "[<span ";
57 
58  if(changed) {
59  ss << "color='#f00' ";
60  }
61 
62  ss << "size='large'>" << font::unicode_bullet << "</span>]";
63  return ss.str();
64 }
65 
67  : locs_(nullptr)
68  , gui_(gui)
69  , game_config_(game_config)
70  , default_dir_(preferences::editor::default_dir())
71  , map_generators_()
72  , last_map_generator_(nullptr)
73  , current_context_index_(0)
74  , auto_update_transitions_(preferences::editor::auto_update_transitions())
75  , map_contexts_()
76  , clipboard_()
77 {
78  resources::filter_con = this;
79 
80  if(default_dir_.empty()) {
82  }
83 
85  init_map_generators(game_config);
86 }
87 
89 {
90  // Restore default window title
92 
93  resources::filter_con = nullptr;
94 }
95 
97 {
99 
100  // TODO register the tod_manager with the gui?
103 
104  gui().init_flags();
105 
106  reload_map();
107 
108  // Enable the labels of the current context;
110 
112 }
113 
115 {
116  gui_.rebuild_all();
122  if(locs_) {
123  for(const auto& loc : get_map_context().map().special_locations().left) {
124  locs_->add_item(loc.first);
125  }
126  if(!get_map_context().is_pure_map()) {
127  // If the scenario has more than 9 teams, add locations for them
128  // (First 9 teams are always in the list)
129  size_t n_teams = get_map_context().teams().size();
130  for(size_t i = 10; i <= n_teams; i++) {
131  locs_->add_item(std::to_string(i));
132  }
133  }
134  }
135 }
136 
138 {
139  gui_.reload_map();
142  refresh_all();
143 }
144 
146 {
147  switch (auto_update_transitions_) {
149  return (item == "editor-auto-update-transitions");
151  return (item == "editor-partial-update-transitions");
153  return (item == "editor-no-update-transitions");
154  }
155 
156  return true; //should not be reached
157 }
158 
160 {
163 
165  return true;
166  }
167 
168  return false;
169 }
170 
171 std::size_t context_manager::modified_maps(std::string& message)
172 {
173  std::vector<std::string> modified;
174  for(auto& mc : map_contexts_) {
175  if(mc->modified()) {
176  if(!mc->get_name().empty()) {
177  modified.push_back(mc->get_name());
178  } else if(!mc->get_filename().empty()) {
179  modified.push_back(mc->get_filename());
180  } else {
181  modified.push_back(mc->get_default_context_name());
182  }
183  }
184  }
185 
186  for(std::string& str : modified) {
187  message += "\n" + font::unicode_bullet + " " + str;
188  }
189 
190  return modified.size();
191 }
192 
193 void context_manager::load_map_dialog(bool force_same_context /* = false */)
194 {
196  if(fn.empty()) {
197  fn = default_dir_;
198  }
199 
201 
202  dlg.set_title(_("Load Map"))
203  .set_path(fn);
204 
205  if(dlg.show()) {
206  load_map(dlg.path(), !force_same_context);
207  }
208 }
209 
210 void context_manager::load_mru_item(unsigned int index, bool force_same_context /* = false */)
211 {
212  const std::vector<std::string>& mru = preferences::editor::recent_files();
213  if(mru.empty() || index >= mru.size()) {
214  return;
215  }
216 
217  load_map(mru[index], !force_same_context);
218 }
219 
221 {
222  team& t = get_map_context().teams()[side_index];
223 
224  editor_team_info team_info(t);
225 
226  if(gui2::dialogs::editor_edit_side::execute(team_info)) {
227  get_map_context().set_side_setup(team_info);
228  }
229 }
230 
232 {
233  map_context& context = get_map_context();
234 
235  // TODO
236  //std::string fn = filesystem::directory_name(context.get_filename());
237 
238  std::string id = context.get_id();
239  std::string name = context.get_name();
240  std::string description = context.get_description();
241 
242  int turns = context.get_time_manager()->number_of_turns();
243  int xp_mod = context.get_xp_mod();
244 
245  bool victory = context.victory_defeated();
246  bool random = context.random_start_time();
247 
248  const bool ok = gui2::dialogs::editor_edit_scenario::execute(
249  id, name, description, turns, xp_mod, victory, random
250  );
251 
252  if(!ok) {
253  return;
254  }
255 
256  context.set_scenario_setup(id, name, description, turns, xp_mod, victory, random);
257 
258  if(!name.empty()) {
260  }
261 }
262 
264 {
265  const editor_map& map = get_map_context().map();
266 
267  int w = map.w();
268  int h = map.h();
269 
270  if(gui2::dialogs::editor_new_map::execute(_("New Map"), w, h)) {
272  new_map(w, h, fill, true);
273  }
274 }
275 
277 {
278  const editor_map& map = get_map_context().map();
279 
280  int w = map.w();
281  int h = map.h();
282 
283  if(gui2::dialogs::editor_new_map::execute(_("New Scenario"), w, h)) {
285  new_scenario(w, h, fill, true);
286  }
287 }
288 
289 void context_manager::expand_open_maps_menu(std::vector<config>& items, int i)
290 {
291  auto pos = items.erase(items.begin() + i);
292  std::vector<config> contexts;
293 
294  for(std::size_t mci = 0; mci < map_contexts_.size(); ++mci) {
295  map_context& mc = *map_contexts_[mci];
296 
297  std::string filename;
298  if(mc.is_pure_map()) {
299  filename = filesystem::base_name(mc.get_filename());
300  } else {
301  filename = mc.get_name();
302  }
303 
304  if(filename.empty()) {
305  filename = mc.get_default_context_name();
306  }
307 
308  std::ostringstream ss;
309  ss << "[" << mci + 1 << "] ";
310 
311  const bool changed = mc.modified();
312 
313  if(changed) {
314  ss << "<i>" << filename << "</i>";
315  } else {
316  ss << filename;
317  }
318 
319  if(mc.is_embedded()) {
320  ss << " (E)";
321  }
322 
323  const std::string label = ss.str();
324  const std::string details = get_menu_marker(changed);
325 
326  contexts.emplace_back("label", label, "details", details);
327  }
328 
329  items.insert(pos, contexts.begin(), contexts.end());
330 }
331 
332 void context_manager::expand_load_mru_menu(std::vector<config>& items, int i)
333 {
334  std::vector<std::string> mru = preferences::editor::recent_files();
335 
336  auto pos = items.erase(items.begin() + i);
337 
338  if(mru.empty()) {
339  items.insert(pos, config {"label", _("No Recent Files")});
340  return;
341  }
342 
343  for(std::string& path : mru) {
344  // TODO: add proper leading ellipsization instead, since otherwise
345  // it'll be impossible to tell apart files with identical names and
346  // different parent paths.
348  }
349 
350  std::vector<config> temp;
351  std::transform(mru.begin(), mru.end(), std::back_inserter(temp), [](const std::string& str) {
352  return config {"label", str};
353  });
354 
355  items.insert(pos, temp.begin(), temp.end());
356 }
357 
358 void context_manager::expand_areas_menu(std::vector<config>& items, int i)
359 {
361  if(!tod) {
362  return;
363  }
364 
365  auto pos = items.erase(items.begin() + i);
366  std::vector<config> area_entries;
367 
368  std::vector<std::string> area_ids = tod->get_area_ids();
369 
370  for(std::size_t mci = 0; mci < area_ids.size(); ++mci) {
371  const std::string& area = area_ids[mci];
372 
373  std::stringstream ss;
374  ss << "[" << mci + 1 << "] ";\
375 
376  if(area.empty()) {
377  ss << "<i>" << _("Unnamed Area") << "</i>";
378  } else {
379  ss << area;
380  }
381 
382  const bool changed =
383  mci == static_cast<std::size_t>(get_map_context().get_active_area())
384  && tod->get_area_by_index(mci) != get_map_context().map().selection();
385 
386  const std::string label = ss.str();
387  const std::string details = get_menu_marker(changed);
388 
389  area_entries.emplace_back("label", label, "details", details);
390  }
391 
392  items.insert(pos, area_entries.begin(), area_entries.end());
393 }
394 
395 void context_manager::expand_sides_menu(std::vector<config>& items, int i)
396 {
397  auto pos = items.erase(items.begin() + i);
398  std::vector<config> contexts;
399 
400  for(std::size_t mci = 0; mci < get_map_context().teams().size(); ++mci) {
401 
402  const team& t = get_map_context().teams()[mci];
403  const std::string& teamname = t.user_team_name();
404  std::stringstream label;
405  label << "[" << mci+1 << "] ";
406 
407  if(teamname.empty()) {
408  label << "<i>" << _("New Side") << "</i>";
409  } else {
410  label << teamname;
411  }
412 
413  contexts.emplace_back("label", label.str());
414  }
415 
416  items.insert(pos, contexts.begin(), contexts.end());
417 }
418 
419 void context_manager::expand_time_menu(std::vector<config>& items, int i)
420 {
421  auto pos = items.erase(items.begin() + i);
422  std::vector<config> times;
423 
425 
426  assert(tod_m != nullptr);
427 
428  for(const time_of_day& time : tod_m->times()) {
429  times.emplace_back(
430  "details", time.name, // Use 'details' field here since the image will take the first column
431  "image", time.image
432  );
433  }
434 
435  items.insert(pos, times.begin(), times.end());
436 }
437 
438 void context_manager::expand_local_time_menu(std::vector<config>& items, int i)
439 {
440  auto pos = items.erase(items.begin() + i);
441  std::vector<config> times;
442 
444 
445  for(const time_of_day& time : tod_m->times(get_map_context().get_active_area())) {
446  times.emplace_back(
447  "details", time.name, // Use 'details' field here since the image will take the first column
448  "image", time.image
449  );
450  }
451 
452  items.insert(pos, times.begin(), times.end());
453 }
454 
456 {
457  std::string fn = get_map_context().get_filename();
458  if(fn.empty()) {
459  fn = default_dir_;
460  }
461 
463 
464  dlg.set_title(_("Apply Mask"))
465  .set_path(fn);
466 
467  if(dlg.show()) {
468  try {
469  map_context mask(game_config_, dlg.path());
470  editor_action_apply_mask a(mask.map());
472  } catch (const editor_map_load_exception& e) {
473  gui2::show_transient_message(_("Error loading mask"), e.what());
474  return;
475  } catch (const editor_action_exception& e) {
477  return;
478  }
479  }
480 }
481 
482 void context_manager::perform_refresh(const editor_action& action, bool drag_part /* =false */)
483 {
485  refresh_after_action(drag_part);
486 }
487 
489 {
490  int active_area = get_map_context().get_active_area();
491  std::string name = get_map_context().get_time_manager()->get_area_ids()[active_area];
492 
493  if(gui2::dialogs::edit_text::execute(N_("Rename Area"), N_("Identifier:"), name)) {
494  get_map_context().get_time_manager()->set_area_id(active_area, name);
495  }
496 }
497 
499 {
500  std::string fn = get_map_context().get_filename();
501  if(fn.empty()) {
502  fn = default_dir_;
503  }
504 
506 
507  dlg.set_title(_("Choose Target Map"))
508  .set_path(fn);
509 
510  if(dlg.show()) {
511  try {
512  map_context map(game_config_, dlg.path());
513  editor_action_create_mask a(map.map());
515  } catch (const editor_map_load_exception& e) {
516  gui2::show_transient_message(_("Error loading map"), e.what());
517  return;
518  } catch (const editor_action_exception& e) {
520  return;
521  }
522  }
523 }
524 
526 {
527  if(get_map_context().needs_reload()) {
528  reload_map();
529  return;
530  }
531 
532  const std::set<map_location>& changed_locs = get_map_context().changed_locations();
533 
534  if(get_map_context().needs_terrain_rebuild()) {
537  && (!drag_part || get_map_context().everything_changed())))
538  {
539  gui_.rebuild_all();
542  } else {
543  for(const map_location& loc : changed_locs) {
544  gui_.rebuild_terrain(loc);
545  }
546  gui_.invalidate(changed_locs);
547  }
548  } else {
549  if(get_map_context().everything_changed()) {
551  } else {
552  gui_.invalidate(changed_locs);
553  }
554  }
555 
556  if(get_map_context().needs_labels_reset()) {
558  }
559 
562 }
563 
565 {
566  const editor_map& map = get_map_context().map();
567 
568  int w = map.w();
569  int h = map.h();
570 
572  bool copy = false;
573 
574  if(!gui2::dialogs::editor_resize_map::execute(w, h, dir, copy)) {
575  return;
576  }
577 
578  if(w != map.w() || h != map.h()) {
580  if(copy) {
582  }
583 
584  int x_offset = map.w() - w;
585  int y_offset = map.h() - h;
586 
587  switch (dir) {
591  y_offset = 0;
592  break;
596  y_offset /= 2;
597  break;
601  break;
602  default:
603  y_offset = 0;
604  WRN_ED << "Unknown resize expand direction" << std::endl;
605  break;
606  }
607 
608  switch (dir) {
612  x_offset = 0;
613  break;
617  x_offset /= 2;
618  break;
622  break;
623  default:
624  x_offset = 0;
625  break;
626  }
627 
628  editor_action_resize_map a(w, h, x_offset, y_offset, fill);
629  perform_refresh(a);
630  }
631 }
632 
634 {
635  std::string input_name = get_map_context().get_filename();
636  if(input_name.empty()) {
637  input_name = filesystem::get_dir(default_dir_ + "/maps");
638  }
639 
641 
642  dlg.set_title(_("Save Map As"))
643  .set_save_mode(true)
644  .set_path(input_name)
645  .set_extension(".map");
646 
647  if(!dlg.show()) {
648  return;
649  }
650 
651  save_map_as(dlg.path());
652 }
653 
655 {
656  std::string input_name = get_map_context().get_filename();
657  if(input_name.empty()) {
658  input_name = filesystem::get_dir(default_dir_ + "/scenarios");
659  }
660 
662 
663  dlg.set_title(_("Save Scenario As"))
664  .set_save_mode(true)
665  .set_path(input_name)
666  .set_extension(".cfg");
667 
668  if(!dlg.show()) {
669  return;
670  }
671 
672  save_scenario_as(dlg.path());
673 }
674 
676 {
677  for(const config& i : game_config.child_range("multiplayer")) {
678  if(i["map_generation"].empty() && i["scenario_generation"].empty()) {
679  continue;
680  }
681 
682  const config& generator_cfg = i.child("generator");
683  if(!generator_cfg) {
684  ERR_ED << "Scenario \"" << i["name"] << "\" with id " << i["id"]
685  << " has map_generation= but no [generator] tag" << std::endl;
686  } else {
687  map_generators_.emplace_back(create_map_generator(i["map_generation"], generator_cfg));
688  }
689  }
690 }
691 
693 {
694  if(map_generators_.empty()) {
695  gui2::show_error_message(_("No random map generators found."));
696  return;
697  }
698 
701 
702  if(dialog.show()) {
703  std::string map_string;
705  try {
706  map_string = map_generator->create_map(dialog.get_seed());
707  } catch (const mapgen_exception& e) {
708  gui2::show_transient_message(_("Map creation failed."), e.what());
709  return;
710  }
711 
712  if(map_string.empty()) {
713  gui2::show_transient_message("", _("Map creation failed."));
714  } else {
715  editor_map new_map(game_config_, map_string);
716  editor_action_whole_map a(new_map);
717  get_map_context().set_needs_labels_reset(); // Ensure Player Start labels are updated together with newly generated map
718  perform_refresh(a);
719  }
720 
721  last_map_generator_ = map_generator;
722  }
723 }
724 
726 {
727  if(get_map_context().modified()) {
728  const int res = gui2::show_message(_("Unsaved Changes"),
729  _("Do you want to discard all changes made to the map since the last save?"), gui2::dialogs::message::yes_no_buttons);
730  return gui2::retval::CANCEL != res;
731  }
732 
733  return true;
734 }
735 
737 {
739 }
740 
741 void context_manager::save_all_maps(bool auto_save_windows)
742 {
743  int current = current_context_index_;
744  saved_windows_.clear();
745  for(std::size_t i = 0; i < map_contexts_.size(); ++i) {
746  switch_context(i);
747  std::string name = get_map_context().get_filename();
748  if(auto_save_windows) {
749  if(name.empty() || filesystem::is_directory(name)) {
750  std::ostringstream s;
751  s << default_dir_ << "/" << "window_" << i + 1;
752  name = s.str();
754  }
755  }
756  saved_windows_.push_back(name);
757  save_map();
758  }
759 
760  switch_context(current);
761 }
762 
764 {
765  const std::string& name = get_map_context().get_filename();
766  if(name.empty() || filesystem::is_directory(name)) {
767  if(get_map_context().is_pure_map()) {
769  } else {
771  }
772  } else {
773  if(get_map_context().is_pure_map()) {
774  write_map();
775  } else {
776  write_scenario();
777  }
778  }
779 }
780 
781 bool context_manager::save_scenario_as(const std::string& filename)
782 {
783  std::size_t is_open = check_open_map(filename);
784  if(is_open < map_contexts_.size() && is_open != static_cast<unsigned>(current_context_index_)) {
785  gui2::show_transient_message(_("This scenario is already open."), filename);
786  return false;
787  }
788 
789  std::string old_filename = get_map_context().get_filename();
790  bool embedded = get_map_context().is_embedded();
791 
792  get_map_context().set_filename(filename);
793  get_map_context().set_embedded(false);
794 
795  if(!write_scenario(true)) {
796  get_map_context().set_filename(old_filename);
797  get_map_context().set_embedded(embedded);
798  return false;
799  }
800 
801  return true;
802 }
803 
804 bool context_manager::save_map_as(const std::string& filename)
805 {
806  std::size_t is_open = check_open_map(filename);
807  if(is_open < map_contexts_.size() && is_open != static_cast<unsigned>(current_context_index_)) {
808  gui2::show_transient_message(_("This map is already open."), filename);
809  return false;
810  }
811 
812  std::string old_filename = get_map_context().get_filename();
813  bool embedded = get_map_context().is_embedded();
814 
815  get_map_context().set_filename(filename);
816  get_map_context().set_embedded(false);
817 
818  if(!write_map(true)) {
819  get_map_context().set_filename(old_filename);
820  get_map_context().set_embedded(embedded);
821  return false;
822  }
823 
824  return true;
825 }
826 
827 bool context_manager::write_scenario(bool display_confirmation)
828 {
829  try {
831  if(display_confirmation) {
832  gui2::show_transient_message("", _("Scenario saved."));
833  }
834  } catch (const editor_map_save_exception& e) {
836  return false;
837  }
838 
839  return true;
840 }
841 
842 bool context_manager::write_map(bool display_confirmation)
843 {
844  try {
846  if(display_confirmation) {
847  gui2::show_transient_message("", _("Map saved."));
848  }
849  } catch (const editor_map_save_exception& e) {
851  return false;
852  }
853 
854  return true;
855 }
856 
857 std::size_t context_manager::check_open_map(const std::string& fn) const
858 {
859  std::size_t i = 0;
860  while(i < map_contexts_.size() && map_contexts_[i]->get_filename() != fn) {
861  ++i;
862  }
863 
864  return i;
865 }
866 
867 bool context_manager::check_switch_open_map(const std::string& fn)
868 {
869  std::size_t i = check_open_map(fn);
870  if(i < map_contexts_.size()) {
871  gui2::show_transient_message(_("This map is already open."), fn);
872  switch_context(i);
873  return true;
874  }
875 
876  return false;
877 }
878 
879 void context_manager::load_map(const std::string& filename, bool new_context)
880 {
881  if(new_context && check_switch_open_map(filename)) {
882  return;
883  }
884 
885  LOG_ED << "Load map: " << filename << (new_context ? " (new)" : " (same)") << "\n";
886  try {
887  {
888  context_ptr mc(new map_context(game_config_, filename));
889  if(mc->get_filename() != filename) {
890  if(new_context && check_switch_open_map(mc->get_filename())) {
891  return;
892  }
893  }
894 
895  if(new_context) {
896  int new_id = add_map_context_of(std::move(mc));
897  switch_context(new_id);
898  } else {
899  replace_map_context_with(std::move(mc));
900  }
901  }
902 
903  if(get_map_context().is_embedded()) {
904  const std::string& msg = _("Loaded embedded map data");
905  gui2::show_transient_message(_("Map loaded from scenario"), msg);
906  } else {
907  if(get_map_context().get_filename() != filename) {
908  if(get_map_context().get_map_data_key().empty()) {
909  ERR_ED << "Internal error, map context filename changed: "
910  << filename << " -> " << get_map_context().get_filename()
911  << " with no apparent scenario load\n";
912  } else {
913  utils::string_map symbols;
914  symbols["old"] = filename;
915  const std::string& msg = _("Loaded referenced map file:\n$new");
916  symbols["new"] = get_map_context().get_filename();
917  symbols["map_data"] = get_map_context().get_map_data_key();
918  gui2::show_transient_message(_("Map loaded from scenario"),
919  //TODO: msg is already translated does vgettext make sense?
920  VGETTEXT(msg.c_str(), symbols));
921  }
922  }
923  }
924  } catch(const editor_map_load_exception& e) {
925  gui2::show_transient_message(_("Error loading map"), e.what());
926  return;
927  }
928 }
929 
931 {
932  if(!confirm_discard()) {
933  return;
934  }
935 
936  std::string filename = get_map_context().get_filename();
937  if(filename.empty()) {
938  ERR_ED << "Empty filename in map revert" << std::endl;
939  return;
940  }
941 
942  load_map(filename, false);
943 }
944 
945 void context_manager::new_map(int width, int height, const t_translation::terrain_code& fill, bool new_context)
946 {
947  const config& default_schedule = game_config_.find_child("editor_times", "id", "default");
948  editor_map m(game_config_, width, height, fill);
949 
950  if(new_context) {
951  int new_id = add_map_context(m, true, default_schedule);
952  switch_context(new_id);
953  } else {
954  replace_map_context(m, true, default_schedule);
955  }
956 }
957 
958 void context_manager::new_scenario(int width, int height, const t_translation::terrain_code& fill, bool new_context)
959 {
960  const config& default_schedule = game_config_.find_child("editor_times", "id", "default");
961  editor_map m(game_config_, width, height, fill);
962 
963  if(new_context) {
964  int new_id = add_map_context(m, false, default_schedule);
965  switch_context(new_id);
966  } else {
967  replace_map_context(m, false, default_schedule);
968  }
969 
970  // Give the new scenario an initial side.
972  gui_.init_flags();
973 }
974 
975 //
976 // Context manipulation
977 //
978 
979 template<typename... T>
980 int context_manager::add_map_context(const T&... args)
981 {
982  map_contexts_.emplace_back(new map_context(args...));
983  return map_contexts_.size() - 1;
984 }
985 
987 {
988  map_contexts_.emplace_back(std::move(mc));
989  return map_contexts_.size() - 1;
990 }
991 
992 template<typename... T>
994 {
995  context_ptr new_mc(new map_context(args...));
996  replace_map_context_with(std::move(new_mc));
997 }
998 
1000 {
1003 }
1004 
1006 {
1007  if(saved_windows_.empty()) {
1010 
1011  const config& default_schedule = game_config_.find_child("editor_times", "id", "default");
1012  add_map_context(editor_map(game_config_, 44, 33, default_terrain), true, default_schedule);
1013  } else {
1014  for(const std::string& filename : saved_windows_) {
1015  add_map_context(game_config_, filename);
1016  }
1017 
1018  saved_windows_.clear();
1019  }
1020 }
1021 
1023 {
1024  if(!confirm_discard()) return;
1025 
1026  if(map_contexts_.size() == 1) {
1028  map_contexts_.erase(map_contexts_.begin());
1029  } else if(current_context_index_ == static_cast<int>(map_contexts_.size()) - 1) {
1030  map_contexts_.pop_back();
1032  } else {
1034  }
1035 
1037 }
1038 
1039 void context_manager::switch_context(const int index, const bool force)
1040 {
1041  if(index < 0 || static_cast<std::size_t>(index) >= map_contexts_.size()) {
1042  WRN_ED << "Invalid index in switch map context: " << index << std::endl;
1043  return;
1044  }
1045 
1046  if(index == current_context_index_ && !force) {
1047  return;
1048  }
1049 
1050  // Disable the labels of the current context before switching.
1051  // The refresher handles enabling the new ones.
1052  get_map_context().get_labels().enable(false);
1053 
1055 
1057 }
1058 
1060 {
1061  std::string name = get_map_context().get_name();
1062 
1063  if(name.empty()) {
1065  }
1066 
1067  if(name.empty()){
1069  }
1070 
1071  const std::string& wm_title_string = name + " - " + game_config::get_default_title_string();
1072  CVideo::get_singleton().set_window_title(wm_title_string);
1073 }
1074 
1075 } //Namespace editor
int auto_update_transitions()
Definition: editor.cpp:24
bool write_scenario(bool display_confirmation=false)
Dialog was closed with the CANCEL button.
Definition: retval.hpp:37
void set_side_setup(editor_team_info &info)
TODO.
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.
Definition: message.cpp:152
const std::string & get_name() const
boost::optional< uint32_t > get_seed()
::tod_manager * tod_manager
Definition: resources.cpp:29
int h() const
Effective map height.
Definition: map.hpp:116
void apply_mask_dialog()
Display an apply mask dialog and process user input.
std::size_t check_open_map(const std::string &fn) const
Check if a map is already open.
bool check_switch_open_map(const std::string &fn)
Check if a map is already open.
std::unique_ptr< map_context > context_ptr
std::size_t modified_maps(std::string &modified)
int auto_update_transitions_
Flag to rebuild terrain on every terrain change.
const t_translation::terrain_code & get_selected_bg_terrain()
std::vector< std::string > recent_files()
Retrieves the list of recently opened files.
Definition: editor.cpp:118
const terrain_code NONE_TERRAIN
Definition: translation.hpp:59
void edit_scenario_dialog()
Display a scenario edit dialog and process user input.
std::map< std::string, t_string > string_map
bool invalidate(const map_location &loc)
Function to invalidate a specific tile for redrawing.
Definition: display.cpp:2994
file_dialog & set_extension(const std::string &value)
Sets the default file extension for file names in save mode.
game_classification * classification
Definition: resources.cpp:34
file_dialog & set_path(const std::string &value)
Sets the initial file selection.
void change_display_context(const display_context *dc)
Definition: display.cpp:499
void replace_map_context_with(context_ptr &&mc)
std::vector< context_ptr > map_contexts_
The currently opened map context object.
config & find_child(config_key_type key, const std::string &name, const std::string &value)
Returns the first child of tag key with a name attribute containing value.
Definition: config.cpp:838
void new_side()
Adds a new side to the map.
void reload_map()
Reload the map after it has significantly changed (when e.g.
bool save_scenario()
Saves the scenario under the current filename.
void resize_map_dialog()
Display a load map dialog and process user input.
#define a
void save_scenario_as_dialog()
Display a save map as dialog and process user input.
void rename_area_dialog()
Display an dialog to querry a new id for an [time_area].
void refresh_after_action(bool drag_part=false)
Refresh the display after an action has been performed.
void init_flags()
Init the flag list and the team colors used by ~TC.
Definition: display.cpp:286
const std::string & get_filename() const
child_itors child_range(config_key_type key)
Definition: config.cpp:366
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, const bool restore_background)
Shows a transient message to the user.
void set_area_id(int area_index, const std::string &id)
context_manager(editor_display &gui, const config &game_config)
map_labels & get_labels()
void save_map()
Save the map, open dialog if not named yet.
#define LOG_ED
General purpose widgets.
std::string default_dir_
Default directory for map load/save as dialogs.
A terrain string which is converted to a terrain is a string with 1 or 2 layers the layers are separa...
Definition: translation.hpp:50
std::string get_default_title_string()
void perform_refresh(const editor_action &action, bool drag_part=false)
Perform an action on the current map_context, then refresh the display.
file_dialog & set_save_mode(bool value)
Sets the dialog&#39;s behavior on non-existent file name inputs.
static CVideo & get_singleton()
Definition: video.hpp:43
#define h
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
const std::vector< std::string > items
int add_map_context(const T &... args)
Add a map context.
Replace contents of the entire map, Useful as a fallback undo method when something else would be imp...
Definition: action.hpp:37
int get_xp_mod() const
-file sdl_utils.hpp
bool show(const unsigned auto_close_time=0)
Shows the window.
bool confirm_discard()
Shows an are-you-sure dialog if the map was modified.
void set_needs_reload(bool value=true)
Setter for the reload flag.
map_context & get_map_context()
Get the current map context object.
void refresh_all()
Refresh everything, i.e.
int add_map_context_of(context_ptr &&mc)
map_generator * get_selected_map_generator()
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.
static bfs::path get_dir(const bfs::path &dirpath)
Definition: filesystem.cpp:282
void revert_map()
Revert the map by reloading it from disk.
const std::string & get_id() const
bool modified() const
void expand_areas_menu(std::vector< config > &items, int i)
Menu expanding for the map&#39;s defined areas.
std::string path() const
Gets the current file selection.
std::string default_dir()
Definition: editor.cpp:32
#define WRN_ED
game_classification & get_classification()
void set_window_title(const std::string &title)
Sets the title of the main window.
Definition: video.cpp:362
Object which defines a time of day with associated bonuses, image, sounds etc.
Definition: time_of_day.hpp:57
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
This class stores all the data for a single &#39;side&#39; (in game nomenclature).
Definition: team.hpp:44
void close_current_context()
Closes the active map context.
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
const std::set< map_location > & selection() const
Return the selection set.
Definition: editor_map.hpp:149
void load_map_dialog(bool force_same_context=false)
Display a load map dialog and process user input.
std::string get_user_data_dir()
Definition: filesystem.cpp:720
void reset_starting_position_labels(display &disp)
void recalculate_minimap()
Schedule the minimap for recalculation.
Definition: display.hpp:615
void select_map_generator(map_generator *mg)
filter_context * filter_con
Definition: resources.cpp:23
void set_embedded(bool v)
const std::set< map_location > changed_locations() const
void set_auto_update_transitions(int value)
Definition: editor.cpp:28
void new_scenario_dialog()
Display a new map dialog and process user input.
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
Definition: filesystem.cpp:955
Editor action classes.
bool random_start_time() const
bool save_map()
Saves the map under the current filename.
void enable(bool is_enabled)
Definition: label.cpp:253
std::string path
Definition: game_config.cpp:39
Modify, read and display user preferences.
Shows a yes and no button.
Definition: message.hpp:79
map_display and display: classes which take care of displaying the map and game-data on the screen...
void refresh_on_context_change()
Performs the necessary housekeeping necessary when switching contexts.
bool is_pure_map() const
void create_buttons()
Definition: display.cpp:864
Manage the empty-palette in the editor.
Definition: action.cpp:29
std::string default_terrain
Definition: game_config.cpp:70
void perform_action(const editor_action &action)
Performs an action (thus modifying the map).
const char * what() const noexcept
Definition: exceptions.hpp:37
void invalidate_all()
Function to invalidate all tiles.
Definition: display.cpp:2984
bool is_active_transitions_hotkey(const std::string &item)
void switch_context(const int index, const bool force=false)
Switches the context to the one under the specified index.
void new_scenario(int width, int height, const t_translation::terrain_code &fill, bool new_context)
Create a new scenario.
Paint the same terrain on a number of locations on the map.
Definition: action.hpp:284
void new_map(int width, int height, const t_translation::terrain_code &fill, bool new_context)
Create a new map.
bool is_embedded() const
int number_of_turns() const
void load_map(const std::string &filename, bool new_context)
Load a map given the filename.
virtual std::string create_map(boost::optional< uint32_t > randomseed=boost::none)=0
Creates a new map and returns it.
std::vector< std::string > get_area_ids() const
map_generator * create_map_generator(const std::string &name, const config &cfg)
Definition: map_create.cpp:28
void set_needs_terrain_rebuild(bool value=true)
Setter for the terrain rebuild flag.
Encapsulates the map of the game.
Definition: location.hpp:42
class location_palette * locs_
const std::string & get_description() const
void clear_changed_locations()
int w() const
Effective map width.
Definition: map.hpp:113
This class adds extra editor-specific functionality to a normal gamemap.
Definition: editor_map.hpp:69
std::size_t i
Definition: function.cpp:933
void add_item(const std::string &id)
void fill_selection()
Fill the selection with the foreground terrain.
void save_map_as_dialog()
Display a save map as dialog and process user input.
bool write_map(bool display_confirmation=false)
Save the map under a given filename.
Game configuration data as global variables.
Definition: build_info.cpp:47
void expand_local_time_menu(std::vector< config > &items, int i)
Menu expanding for the map&#39;s defined areas.
void rebuild_terrain(const map_location &loc)
bool save_scenario_as(const std::string &filename)
const tod_manager * get_time_manager() const
static map_location::DIRECTION s
const std::vector< time_of_day > & times(const map_location &loc=map_location::null_location()) const
editor_display & gui()
Base class for all editor actions.
Definition: action_base.hpp:40
void save_all_maps(bool auto_save_windows=false)
Save all maps, open dialog if not named yet, except when using auto_save_windows which will name unna...
const std::string & get_map_data_key() const
void create_mask_to_dialog()
Display an apply mask dialog and process user input.
Declarations for File-IO.
int w
This class wraps around a map to provide a concise interface for the editor to work with...
Definition: map_context.hpp:55
#define N_(String)
Definition: gettext.hpp:97
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.
Definition: unicode.cpp:71
const std::string unicode_bullet
Definition: constants.cpp:43
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
void replace_map_context(const T &... args)
Replace the current map context and refresh accordingly.
std::string base_name(const std::string &file, const bool remove_extension)
Returns the base filename of a file, with directory name stripped.
void expand_sides_menu(std::vector< config > &items, int i)
Menu expanding for the map&#39;s player sides.
bool victory_defeated() const
static std::string get_filename(const std::string &file_code)
map_generator * last_map_generator_
int turns()
Definition: game.cpp:558
void edit_side_dialog(int side_index)
Display a side edit dialog and process user input.
double t
Definition: astarsearch.cpp:64
void reload_map()
Updates internals that cache map size.
Definition: display.cpp:493
virtual const editor_map & map() const override
Const map accessor.
lu_byte left
Definition: lparser.cpp:1026
int get_active_area() const
#define ERR_ED
void set_needs_labels_reset(bool value=true)
Setter for the labels reset flag.
std::vector< std::unique_ptr< map_generator > > map_generators_
Available random map generators.
void set_filename(const std::string &fn)
void expand_load_mru_menu(std::vector< config > &items, int i)
Menu expanding for most recent loaded list.
const std::set< map_location > & get_area_by_index(int index) const
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
Definition: message.cpp:205
void generate_map_dialog()
Display a generate random map dialog and process user input.
void set_window_title()
Displays the specified map name in the window titlebar.
void create_default_context()
Creates a default map context object, used to ensure there is always at least one.
The dialog for selecting which random generator to use in the editor.
#define e
bool save_map_as(const std::string &filename)
Save the map under a given filename.
void expand_time_menu(std::vector< config > &items, int i)
Menu expanding for the map&#39;s defined areas.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
void init_map_generators(const config &game_config)
init available random map generators
void load_mru_item(unsigned index, bool force_same_context=false)
Open the specified entry from the recent files list.
virtual const std::vector< team > & teams() const override
Const teams accessor.
static std::vector< std::string > saved_windows_
static const std::string get_menu_marker(const bool changed)
void expand_open_maps_menu(std::vector< config > &items, int i)
Menu expanding for open maps list.
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
const t_string & user_team_name() const
Definition: team.hpp:297
terrain_code read_terrain_code(const std::string &str, const ter_layer filler)
Reads a single terrain from a string.
const t_string get_default_context_name() const
void rebuild_all()
Rebuild all dynamic terrain.
Definition: display.cpp:488
void new_map_dialog()
Display a new map dialog and process user input.
file_dialog & set_title(const std::string &value)
Sets the current dialog title text.
Definition: file_dialog.hpp:56