The Battle for Wesnoth  1.19.5+dev
editor_controller.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2024
3  by Tomasz Sniatowski <kailoran@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #define GETTEXT_DOMAIN "wesnoth-editor"
17 
19 
20 #include "desktop/open.hpp"
21 
22 #include "editor/action/action.hpp"
26 
29 
31 
33 
39 #include "gui/dialogs/message.hpp"
43 #include "wml_exception.hpp"
44 
45 #include "resources.hpp"
46 #include "reports.hpp"
47 
48 #include "cursor.hpp"
49 #include "desktop/clipboard.hpp"
50 #include "floating_label.hpp"
51 #include "gettext.hpp"
52 #include "picture.hpp"
53 #include "sound.hpp"
54 #include "units/unit.hpp"
56 #include "quit_confirmation.hpp"
57 #include "sdl/input.hpp" // get_mouse_button_mask
58 #include "serialization/chrono.hpp"
59 
60 #include <functional>
61 
62 namespace {
63 static std::vector<std::string> saved_windows_;
64 }
65 
66 namespace editor {
67 
69 
71  : controller_base()
72  , mouse_handler_base()
73  , quit_confirmation(std::bind(&editor_controller::quit_confirm, this))
74  , active_menu_(editor::MAP)
75  , reports_(new reports())
76  , gui_(new editor_display(*this, *reports_))
77  , tods_()
78  , context_manager_(new context_manager(*gui_.get(), game_config_, clear_id ? "" : editor_controller::current_addon_id_))
79  , toolkit_(nullptr)
80  , tooltip_manager_()
81  , floating_label_manager_(nullptr)
82  , help_manager_(nullptr)
83  , do_quit_(false)
84  , quit_mode_(EXIT_ERROR)
85  , music_tracks_()
86 {
87  if(clear_id) {
89  }
90 
91  init_gui();
92  toolkit_.reset(new editor_toolkit(*gui_.get(), key_, game_config_, *context_manager_.get()));
94  context_manager_->locs_ = toolkit_->get_palette_manager()->location_palette_.get();
99 
100  gui().queue_rerender();
101 }
102 
104 {
105  gui_->change_display_context(&get_current_map_context());
106  gui_->add_redraw_observer(std::bind(&editor_controller::display_redraw_callback, this, std::placeholders::_1));
108  gui().set_debug_flag(display::DEBUG_COORDINATES, prefs::get().editor_draw_hex_coordinates());
109  gui().set_debug_flag(display::DEBUG_TERRAIN_CODES, prefs::get().editor_draw_terrain_codes());
110  gui().set_debug_flag(display::DEBUG_NUM_BITMAPS, prefs::get().editor_draw_num_of_bitmaps());
111  gui().set_help_string_enabled(prefs::get().editor_help_text_shown());
112 // halo_manager_.reset(new halo::manager(*gui_));
113 // resources::halo = halo_manager_.get();
114 // ^ These lines no longer necessary, the gui owns its halo manager.
115 // TODO: Should the editor map contexts actually own the halo manager and swap them in and out from the gui?
116 // Note that if that is what happens it might not actually be a good idea for the gui to own the halo manager, so that it can be swapped out
117 // without deleting it.
118 }
119 
121 {
122  for (const config &schedule : game_config.child_range("editor_times")) {
123 
124  const std::string& schedule_id = schedule["id"];
125  /* Use schedule id as the name if schedule name is empty */
126  const std::string& schedule_name = schedule["name"].empty() ? schedule["id"] : schedule["name"];
127  if (schedule_id.empty()) {
128  ERR_ED << "Missing ID attribute in a TOD Schedule.";
129  continue;
130  }
131 
132  tods_map::iterator times = tods_.find(schedule_id);
133  if (times == tods_.end()) {
134  std::pair<tods_map::iterator, bool> new_times =
135  tods_.emplace(schedule_id, std::pair(schedule_name, std::vector<time_of_day>()));
136  times = new_times.first;
137  } else {
138  ERR_ED << "Duplicate TOD Schedule identifiers.";
139  continue;
140  }
141 
142  for (const config &time : schedule.child_range("time")) {
143  times->second.second.emplace_back(time);
144  }
145 
146  }
147 
148  if (tods_.empty()) {
149  ERR_ED << "No editor time-of-day defined";
150  }
151 }
152 
154 {
155  const std::string tag_name = "editor_music";
156  if (game_config.child_range(tag_name).size() == 0) {
157  ERR_ED << "No editor music defined";
158  }
159  else {
160  for (const config& editor_music : game_config.child_range(tag_name)) {
161  for (const config& music : editor_music.child_range("music")) {
162  sound::music_track track(music);
163  if (track.file_path().empty())
164  WRN_ED << "Music track " << track.id() << " not found.";
165  else
166  music_tracks_.emplace_back(music);
167  }
168  }
169  }
170 }
171 
173 {
174  resources::tod_manager = nullptr;
175  resources::filter_con = nullptr;
176 
177  resources::classification = nullptr;
178 }
179 
181 {
182  try {
183  while (!do_quit_) {
184  play_slice();
185  }
186  } catch (const editor_exception& e) {
187  gui2::show_transient_message(_("Fatal error"), e.what());
188  return EXIT_ERROR;
189  } catch (const wml_exception& e) {
190  e.show();
191  }
192  return quit_mode_;
193 }
194 
196 }
197 
198 void editor_controller::do_screenshot(const std::string& screenshot_filename /* = "map_screenshot.png" */)
199 {
200  try {
201  surface screenshot = gui().screenshot(true);
202  if(!screenshot || image::save_image(screenshot, screenshot_filename) != image::save_result::success) {
203  ERR_ED << "Screenshot creation failed!";
204  }
205  } catch (const wml_exception& e) {
206  e.show();
207  }
208 }
209 
211 {
212  std::string modified;
213  std::size_t amount = context_manager_->modified_maps(modified);
214 
215  std::string message;
216  if (amount == 0) {
217  message = _("Do you really want to quit?");
218  } else if (amount == 1 && get_current_map_context().modified()) {
219  message = _("Do you really want to quit? Changes to this map since the last save will be lost.");
220  } else {
221  message = _("Do you really want to quit? The following maps were modified and all changes since the last save will be lost:");
222  message += "\n" + modified;
223  }
224  return quit_confirmation::show_prompt(message);
225 }
226 
228 {
230  if (unit_dlg.show()) {
231  unit_dlg.write();
232  }
233 }
234 
236 {
237  if (tods_.empty()) {
238  gui2::show_error_message(_("No editor time-of-day found."));
239  return;
240  }
241 
243  std::vector<time_of_day> prev_schedule = manager.times();
244 
245  gui2::dialogs::custom_tod tod_dlg(manager.times(), manager.get_current_time(), current_addon_id_);
246 
247  /* Register callback to the dialog so that the map changes can be
248  * previewed in real time.
249  */
250  std::function<void(std::vector<time_of_day>)> update_func(
251  std::bind(
253  this,
254  std::placeholders::_1));
255  tod_dlg.register_callback(update_func);
256 
257  /* Autogenerate schedule id */
258  static constexpr std::string_view ts_format = "%Y-%m-%d_%H-%M-%S";
259  std::string timestamp = chrono::format_local_timestamp(std::chrono::system_clock::now(), ts_format);
260  std::string sch_id = current_addon_id_+"-schedule";
261  /* Set correct textdomain */
262  t_string sch_name("", "wesnoth-"+current_addon_id_);
263 
264  // TODO : Needs better error handling messages
265  /* Show dialog and update current schedule */
266  if(tod_dlg.show()) {
267  /* Save the new schedule */
268  std::vector<time_of_day> schedule = tod_dlg.get_schedule();
269  if(!gui2::dialogs::tod_new_schedule::execute(sch_id, sch_name)) {
270  /* User pressed Cancel. Restore old schedule */
271  update_map_schedule(prev_schedule);
272  return;
273  }
274 
275  /* In case the ID or Name field is blank and user presses OK */
276  if (sch_id.empty()) {
277  sch_id = current_addon_id_ + "-schedule-" + timestamp;
278  } else {
279  /* Check if the id entered is same as any of the existing ids
280  * If so, replace */
281  // TODO : Notify the user if they enter an already existing schedule ID
282  for (auto map_elem : tods_) {
283  if (sch_id == map_elem.first) {
284  sch_id = current_addon_id_ + "-schedule-" + timestamp;
285  }
286  }
287  }
288 
289  tods_.emplace(sch_id, std::pair(sch_name, schedule));
291  get_current_map_context().save_schedule(sch_id, sch_name);
292  gui_->update_tod();
293  context_manager_->refresh_all();
294  } else {
295  /* Restore old schedule */
296  update_map_schedule(prev_schedule);
297  }
298 }
299 
300 void editor_controller::update_map_schedule(std::vector<time_of_day> schedule)
301 {
303  gui_->update_tod();
304  context_manager_->refresh_all();
305 }
306 
308 {
309  using namespace hotkey; //reduce hotkey:: clutter
310  int index = cmd.index;
311  switch(cmd.hotkey_command) {
312  case HOTKEY_NULL:
313  if (index >= 0) {
314  unsigned i = static_cast<unsigned>(index);
315 
316  switch (active_menu_) {
317  case editor::MAP:
318  if (i < context_manager_->open_maps()) {
319  return true;
320  }
321  return false;
322  case editor::LOAD_MRU:
323  case editor::PALETTE:
324  case editor::AREA:
325  case editor::ADDON:
326  case editor::SIDE:
327  case editor::TIME:
328  case editor::SCHEDULE:
330  case editor::MUSIC:
331  case editor::LOCAL_TIME:
332  case editor::UNIT_FACING:
333  return true;
334  }
335  }
336  return false;
338  return true;
340  return toolkit_->get_palette_manager()->can_scroll_up();
342  return toolkit_->get_palette_manager()->can_scroll_down();
343  case HOTKEY_ZOOM_IN:
344  return !gui_->zoom_at_max();
345  case HOTKEY_ZOOM_OUT:
346  return !gui_->zoom_at_min();
347  case HOTKEY_ZOOM_DEFAULT:
348  case HOTKEY_FULLSCREEN:
349  case HOTKEY_SCREENSHOT:
351  case HOTKEY_TOGGLE_GRID:
352  case HOTKEY_MOUSE_SCROLL:
353  case HOTKEY_ANIMATE_MAP:
354  case HOTKEY_MUTE:
355  case HOTKEY_PREFERENCES:
356  case HOTKEY_HELP:
357  case HOTKEY_QUIT_GAME:
358  case HOTKEY_SCROLL_UP:
359  case HOTKEY_SCROLL_DOWN:
360  case HOTKEY_SCROLL_LEFT:
361  case HOTKEY_SCROLL_RIGHT:
362  return true; //general hotkeys we can always do
363 
364  case HOTKEY_UNIT_LIST:
365  return !get_current_map_context().units().empty();
366 
367  // TODO Disabling this for now until the functionality can be implemnted.
368  // See the status_table() method
369  case HOTKEY_STATUS_TABLE:
370  //return !get_current_map_context().teams().empty();
371  return false;
372  /////////////////////////////
373 
375  return gui().mouseover_hex().valid();
376 
377  // unit tool related
378  case HOTKEY_DELETE_UNIT:
379  case HOTKEY_RENAME_UNIT:
386  {
387  map_location loc = gui_->mouseover_hex();
388  const unit_map& units = get_current_map_context().units();
389  return (toolkit_->is_mouse_action_set(HOTKEY_EDITOR_TOOL_UNIT) &&
390  units.find(loc) != units.end());
391  }
392 
393  case HOTKEY_UNDO:
396  case HOTKEY_REDO:
398 
405  return true;
406 
407  // Can be enabled as long as a valid addon_id is set
409  return !current_addon_id_.empty();
410 
411  // Only enable when editing a scenario
415 
416  case HOTKEY_EDITOR_PBL:
420  return true;
421 
425 
428  return !get_current_map_context().teams().empty();
429 
430  // brushes
438 
440  return true;
442  return toolkit_->get_palette_manager()->active_palette().supports_swap();
446  {
447  std::string dummy;
448  return context_manager_->modified_maps(dummy) > 1;
449  }
455  return true;
457  return !get_current_map_context().get_filename().empty()
459 
460  // Tools
461  // Pure map editing tools this can be used all the time.
466  return true;
467  // WWL dependent tools which don't rely on defined sides.
474  return !get_current_map_context().teams().empty();
475 
479  return !get_current_map_context().is_pure_map() &&
481 
483  return !get_current_map_context().is_pure_map() &&
485  && !get_current_map_context().map().selection().empty();
486 
491  return !get_current_map_context().map().selection().empty()
492  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
494  return (get_current_map_context().map().selection().size() > 1
495  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE));
499  return !context_manager_->clipboard_empty();
504  return !context_manager_->clipboard_empty()
505  && toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
508  return !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
510  return !get_current_map_context().map().selection().empty()
512  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
530  return true;
534  return true;
535  default:
536  return false;
537  }
538 }
539 
541 {
542  using namespace hotkey;
543  int index = cmd.index;
544  switch (cmd.hotkey_command) {
545 
547  {
549  get_current_map_context().units().find(gui_->mouseover_hex());
550  return un->loyal() ? ACTION_ON : ACTION_OFF;
551 
552  }
554  {
556  get_current_map_context().units().find(gui_->mouseover_hex());
557  return un->can_recruit() ? ACTION_ON : ACTION_OFF;
558  }
560  {
562  get_current_map_context().units().find(gui_->mouseover_hex());
563  return (!un->unrenamable()) ? ACTION_ON : ACTION_OFF;
564  }
565  //TODO remove hardcoded hotkey names
567  return context_manager_->is_active_transitions_hotkey("editor-auto-update-transitions")
570  return context_manager_->is_active_transitions_hotkey("editor-partial-update-transitions")
573  return context_manager_->is_active_transitions_hotkey("editor-no-update-transitions")
576  return toolkit_->is_active_brush("brush-1") ? ACTION_ON : ACTION_OFF;
578  return toolkit_->is_active_brush("brush-2") ? ACTION_ON : ACTION_OFF;
580  return toolkit_->is_active_brush("brush-3") ? ACTION_ON : ACTION_OFF;
582  return toolkit_->is_active_brush("brush-nw-se") ? ACTION_ON : ACTION_OFF;
584  return toolkit_->is_active_brush("brush-sw-ne") ? ACTION_ON : ACTION_OFF;
585 
586  case HOTKEY_TOGGLE_GRID:
587  return prefs::get().grid() ? ACTION_ON : ACTION_OFF;
592  return get_current_map_context().map().selection().empty() ?
603  return toolkit_->is_mouse_action_set(cmd.hotkey_command) ? ACTION_ON : ACTION_OFF;
605  return gui_->debug_flag_set(display::DEBUG_COORDINATES) ? ACTION_ON : ACTION_OFF;
607  return gui_->debug_flag_set(display::DEBUG_TERRAIN_CODES) ? ACTION_ON : ACTION_OFF;
609  return gui_->debug_flag_set(display::DEBUG_NUM_BITMAPS) ? ACTION_ON : ACTION_OFF;
611  return gui_->help_string_enabled() ? ACTION_ON : ACTION_OFF;
613  return (prefs::get().minimap_draw_villages()) ? ACTION_ON : ACTION_OFF;
615  return (prefs::get().minimap_movement_coding()) ? ACTION_ON : ACTION_OFF;
617  return (prefs::get().minimap_terrain_coding()) ? ACTION_ON : ACTION_OFF;
619  return (prefs::get().minimap_draw_units()) ? ACTION_ON : ACTION_OFF;
621  return (prefs::get().minimap_draw_terrain()) ? ACTION_ON : ACTION_OFF;
622  case HOTKEY_ZOOM_DEFAULT:
623  return (gui_->get_zoom_factor() == 1.0) ? ACTION_ON : ACTION_OFF;
624 
625  case HOTKEY_NULL:
626  switch (active_menu_) {
627  case editor::MAP:
628  return index == context_manager_->current_context_index()
630  case editor::LOAD_MRU:
631  return ACTION_STATELESS;
632  case editor::PALETTE:
633  return ACTION_STATELESS;
634  case editor::AREA:
637  case editor::ADDON:
638  return ACTION_STATELESS;
639  case editor::SIDE:
640  return static_cast<std::size_t>(index) == gui_->playing_team_index()
642  case editor::TIME:
645  case editor::LOCAL_TIME:
647  get_current_map_context().get_active_area())
649  case editor::MUSIC:
651  ? ACTION_ON : ACTION_OFF;
652  case editor::SCHEDULE:
653  {
654  tods_map::const_iterator it = tods_.begin();
655  std::advance(it, index);
656  const std::vector<time_of_day>& times1 = it->second.second;
657  const std::vector<time_of_day>& times2 = get_current_map_context().get_time_manager()->times();
658  return (times1 == times2) ? ACTION_SELECTED : ACTION_DESELECTED;
659  }
661  {
662  tods_map::const_iterator it = tods_.begin();
663  std::advance(it, index);
664  const std::vector<time_of_day>& times1 = it->second.second;
665  int active_area = get_current_map_context().get_active_area();
666  const std::vector<time_of_day>& times2 = get_current_map_context().get_time_manager()->times(active_area);
667  return (times1 == times2) ? ACTION_SELECTED : ACTION_DESELECTED;
668  }
669  case editor::UNIT_FACING:
670  {
672  assert(un != get_current_map_context().units().end());
674  }
675  }
676  return ACTION_ON;
677  default:
678  return command_executor::get_action_state(cmd);
679  }
680 }
681 
682 bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool press, bool release)
683 {
684  using namespace hotkey;
685  HOTKEY_COMMAND command = cmd.hotkey_command;
686  SCOPE_ED;
687  int index = cmd.index;
688 
689  // nothing here handles release; fall through to base implementation
690  if (!press) {
691  return command_executor::do_execute_command(cmd, press, release);
692  }
693 
694  switch (command) {
695  case HOTKEY_NULL:
696  switch (active_menu_) {
697  case MAP:
698  if (index >= 0) {
699  unsigned i = static_cast<unsigned>(index);
700  if (i < context_manager_->size()) {
701  context_manager_->switch_context(index);
702  toolkit_->hotkey_set_mouse_action(HOTKEY_EDITOR_TOOL_PAINT);
703  return true;
704  }
705  }
706  return false;
707  case LOAD_MRU:
708  if (index >= 0) {
709  context_manager_->load_mru_item(static_cast<unsigned>(index));
710  }
711  return true;
712  case PALETTE:
713  toolkit_->get_palette_manager()->set_group(index);
714  return true;
715  case SIDE:
716  gui_->set_viewing_team_index(index, true);
717  gui_->set_playing_team_index(index);
718  toolkit_->get_palette_manager()->draw_contents();
719  return true;
720  case AREA:
721  {
723  const std::set<map_location>& area =
726  gui_->scroll_to_tiles({ area.begin(), area.end() });
727  return true;
728  }
729  case ADDON:
730  return true;
731  case TIME:
732  {
734  gui_->update_tod();
735  return true;
736  }
737  case LOCAL_TIME:
738  {
740  return true;
741  }
742  case MUSIC:
743  {
744  //TODO mark the map as changed
747  std::vector<config> items;
748  items.emplace_back("id", "editor-playlist");
749  std::shared_ptr<gui::button> b = gui_->find_menu_button("menu-playlist");
750  show_menu(items, b->location().x +1, b->location().y + b->height() +1, false, *gui_);
751  return true;
752  }
753  case SCHEDULE:
754  {
755  tods_map::iterator iter = tods_.begin();
756  std::advance(iter, index);
757  get_current_map_context().replace_schedule(iter->second.second);
758  // TODO: test again after the assign-schedule menu is fixed. Should work, though.
759  gui_->update_tod();
760  return true;
761  }
762  case LOCAL_SCHEDULE:
763  {
764  tods_map::iterator iter = tods_.begin();
765  std::advance(iter, index);
766  get_current_map_context().replace_local_schedule(iter->second.second);
767  return true;
768  }
769  case UNIT_FACING:
770  {
772  assert(un != get_current_map_context().units().end());
773  un->set_facing(map_location::direction(index));
774  un->anim_comp().set_standing();
775  active_menu_ = MAP;
776  return true;
777  }
778  }
779  return true;
780 
781  //Zoom
782  case HOTKEY_ZOOM_IN:
783  gui_->set_zoom(true);
785  toolkit_->set_mouseover_overlay(*gui_);
786  return true;
787  case HOTKEY_ZOOM_OUT:
788  gui_->set_zoom(false);
790  toolkit_->set_mouseover_overlay(*gui_);
791  return true;
792  case HOTKEY_ZOOM_DEFAULT:
793  gui_->toggle_default_zoom();
795  toolkit_->set_mouseover_overlay(*gui_);
796  return true;
797 
798  //Palette
800  //TODO this code waits for the gui2 dialog to get ready
801  // std::vector< std::pair< std::string, std::string >> blah_items;
802  // toolkit_->get_palette_manager()->active_palette().expand_palette_groups_menu(blah_items);
803  // int selected = 1; //toolkit_->get_palette_manager()->active_palette().get_selected;
804  // gui2::teditor_select_palette_group::execute(selected, blah_items);
805  return true;
807  toolkit_->get_palette_manager()->scroll_up();
808  return true;
810  toolkit_->get_palette_manager()->scroll_down();
811  return true;
812 
813  case HOTKEY_QUIT_GAME:
815  do_quit_ = true;
817  }
818  return true;
821  return true;
823  context_manager_->save_contexts();
824  do_quit_ = true;
826  return true;
829  return true;
832  return true;
834  toolkit_->get_palette_manager()->active_palette().swap();
835  return true;
837  if (dynamic_cast<const editor_action_chain*>(get_current_map_context().last_undo_action()) != nullptr) {
839  context_manager_->refresh_after_action();
840  } else {
841  undo();
842  }
843  return true;
844 
845  //Tool Selection
854  toolkit_->hotkey_set_mouse_action(command);
855  return true;
856 
857  case HOTKEY_EDITOR_PBL:
858  if(initialize_addon()) {
859  context_manager_->edit_pbl();
860  }
861  return true;
862 
864  if(initialize_addon()) {
865  context_manager_->change_addon_id();
866  }
867  return true;
868 
871  return true;
872 
874  {
875  if (!initialize_addon()) {
876  gui2::show_error_message("Could not initialize add-on!");
877  return true;
878  }
879 
881 
882  dlg.set_title(_("Add-on Files"))
884 
885  if (dlg.show()) {
886  std::string filepath = dlg.path();
887  if (filesystem::is_map(filepath) || filesystem::is_cfg(filepath)) {
888  // Open map or scenario
889  context_manager_->load_map(filepath, true);
890  } else {
891  // Open file using OS application for that format
893  desktop::open_object(filepath);
894  } else {
895  gui2::show_message("", _("Opening files is not supported, contact your packager"), gui2::dialogs::message::auto_close);
896  }
897  }
898  }
899 
900  return true;
901  }
902 
904  add_area();
905  return true;
906 
908  change_unit_id();
909  return true;
910 
911  return true;
913  {
914  map_location loc = gui_->mouseover_hex();
916  bool unrenamable = un->unrenamable();
917  un->set_unrenamable(!unrenamable);
918  }
919  return true;
921  {
922  map_location loc = gui_->mouseover_hex();
924  bool canrecruit = un->can_recruit();
925  un->set_can_recruit(!canrecruit);
926  un->anim_comp().set_standing();
927  }
928  return true;
930  {
931  map_location loc = gui_->mouseover_hex();
933  bool loyal = un->loyal();
934  un->set_loyal(!loyal);
935  }
936  return true;
937  case HOTKEY_DELETE_UNIT:
938  {
939  map_location loc = gui_->mouseover_hex();
940  perform_delete(std::make_unique<editor_action_unit_delete>(loc));
941  }
942  return true;
943  case HOTKEY_EDITOR_CLIPBOARD_PASTE: //paste is somewhat different as it might be "one action then revert to previous mode"
944  toolkit_->hotkey_set_mouse_action(command);
945  return true;
946 
947  //Clipboard
949  context_manager_->get_clipboard().rotate_60_cw();
950  toolkit_->update_mouse_action_highlights();
951  return true;
953  context_manager_->get_clipboard().rotate_60_ccw();
954  toolkit_->update_mouse_action_highlights();
955  return true;
957  context_manager_->get_clipboard().flip_horizontal();
958  toolkit_->update_mouse_action_highlights();
959  return true;
961  context_manager_->get_clipboard().flip_vertical();
962  toolkit_->update_mouse_action_highlights();
963  return true;
964 
965  //Brushes
967  toolkit_->cycle_brush();
968  return true;
970  toolkit_->set_brush("brush-1");
971  return true;
973  toolkit_->set_brush("brush-2");
974  return true;
976  toolkit_->set_brush("brush-3");
977  return true;
979  toolkit_->set_brush("brush-nw-se");
980  return true;
982  toolkit_->set_brush("brush-sw-ne");
983  return true;
984 
986  copy_selection();
987  return true;
989  cut_selection();
990  return true;
992  context_manager_->rename_area_dialog();
993  return true;
995  save_area();
996  return true;
999  return true;
1001  if(!get_current_map_context().map().everything_selected()) {
1002  context_manager_->perform_refresh(editor_action_select_all());
1003  return true;
1004  }
1005  [[fallthrough]];
1007  context_manager_->perform_refresh(editor_action_select_inverse());
1008  return true;
1010  context_manager_->perform_refresh(editor_action_select_none());
1011  return true;
1013  context_manager_->fill_selection();
1014  return true;
1017  get_current_map_context().map().selection()));
1018  return true;
1019 
1021  context_manager_->edit_scenario_dialog();
1022  return true;
1023 
1026  get_current_map_context().get_active_area());
1027  return true;
1028 
1029  // map specific
1031  context_manager_->close_current_context();
1032  // Copy behaviour from when switching windows to always reset the active tool to the Paint Tool
1033  // This avoids the situation of having a scenario-specific tool active in a map context which can cause a crash if used
1034  // Not elegant but at least avoids a potential crash and is consistent with existing behaviour
1035  toolkit_->hotkey_set_mouse_action(HOTKEY_EDITOR_TOOL_PAINT);
1036  return true;
1038  context_manager_->load_map_dialog();
1039  return true;
1041  context_manager_->revert_map();
1042  return true;
1043  case HOTKEY_EDITOR_MAP_NEW:
1044  context_manager_->new_map_dialog();
1045  return true;
1047  if(initialize_addon()) {
1048  context_manager_->new_scenario_dialog();
1049  }
1050  return true;
1052  save_map();
1053  return true;
1055  context_manager_->save_all_maps();
1056  return true;
1058  context_manager_->save_map_as_dialog();
1059  return true;
1061  if(initialize_addon()) {
1062  context_manager_->save_scenario_as_dialog();
1063  }
1064  return true;
1066  context_manager_->generate_map_dialog();
1067  return true;
1069  context_manager_->apply_mask_dialog();
1070  return true;
1072  context_manager_->create_mask_to_dialog();
1073  return true;
1075  context_manager_->resize_map_dialog();
1076  return true;
1077 
1078  // Side specific ones
1080  if(get_current_map_context().teams().size() >= 9) {
1081  size_t new_side_num = get_current_map_context().teams().size() + 1;
1082  toolkit_->get_palette_manager()->location_palette_->add_item(std::to_string(new_side_num));
1083  }
1085  gui_->init_flags();
1086  return true;
1088  gui_->set_viewing_team_index(0, true);
1089  gui_->set_playing_team_index(0);
1091  return true;
1093  context_manager_->edit_side_dialog(gui_->viewing_team());
1094  return true;
1095 
1096  // Transitions
1098  context_manager_->set_update_transitions_mode(2);
1099  return true;
1101  context_manager_->set_update_transitions_mode(1);
1102  return true;
1104  context_manager_->set_update_transitions_mode(0);
1105  return true;
1107  if(context_manager_->toggle_update_transitions()) {
1108  return true;
1109  }
1110  [[fallthrough]];
1112  context_manager_->refresh_all();
1113  return true;
1114  // Refresh
1115  case HOTKEY_EDITOR_REFRESH:
1116  context_manager_->reload_map();
1117  return true;
1120  return true;
1121 
1124  prefs::get().set_editor_draw_hex_coordinates(gui().debug_flag_set(display::DEBUG_COORDINATES));
1125  gui().invalidate_all();
1126  return true;
1129  prefs::get().set_editor_draw_terrain_codes(gui().debug_flag_set(display::DEBUG_TERRAIN_CODES));
1130  gui().invalidate_all();
1131  return true;
1134  prefs::get().set_editor_draw_num_of_bitmaps(gui().debug_flag_set(display::DEBUG_NUM_BITMAPS));
1135  gui().invalidate_all();
1136  return true;
1138  gui().set_help_string_enabled(!gui().help_string_enabled());
1139  prefs::get().set_editor_help_text_shown(gui().help_string_enabled());
1140  return true;
1142  location_palette* lp = dynamic_cast<location_palette*>(&toolkit_->get_palette_manager()->active_palette());
1143  if (lp) {
1144  perform_delete(std::make_unique<editor_action_starting_position>(map_location(), lp->selected_item()));
1145  // No idea if this is the right thing to call, but it ensures starting
1146  // position labels get removed on delete.
1147  context_manager_->refresh_after_action();
1148  }
1149  return true;
1150  }
1151  default:
1152  return hotkey::command_executor::do_execute_command(cmd, press, release);
1153  }
1154 }
1155 
1157  if(current_addon_id_.empty()) {
1158  // editor::initialize_addon can return empty id in case of failure
1160  }
1161  context_manager_->set_addon_id(current_addon_id_);
1162  return !current_addon_id_.empty();
1163 }
1164 
1166 {
1167  help::show_help("..editor");
1168 }
1169 
1170 void editor_controller::show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& disp)
1171 {
1172  if(context_menu) {
1173  if(!get_current_map_context().map().on_board_with_border(gui().hex_clicked_on(xloc, yloc))) {
1174  return;
1175  }
1176  }
1177 
1178  std::vector<config> items;
1179  for(const auto& c : items_arg) {
1180  const std::string& id = c["id"];
1181 
1183 
1184  if((can_execute_command(cmd) && (!context_menu || in_context_menu(cmd)))
1186  {
1187  items.emplace_back("id", id);
1188  }
1189  }
1190 
1191  // No point in showing an empty menu.
1192  if(items.empty()) {
1193  return;
1194  }
1195 
1196  // Based on the ID of the first entry, we fill the menu contextually.
1197  const std::string& first_id = items.front()["id"];
1198 
1199  if(first_id == "EDITOR-LOAD-MRU-PLACEHOLDER") {
1201  context_manager_->expand_load_mru_menu(items, 0);
1202  }
1203 
1204  if(first_id == "editor-switch-map") {
1206  context_manager_->expand_open_maps_menu(items, 0);
1207  }
1208 
1209  if(first_id == "editor-palette-groups") {
1211  toolkit_->get_palette_manager()->active_palette().expand_palette_groups_menu(items, 0);
1212  }
1213 
1214  if(first_id == "editor-switch-side") {
1216  context_manager_->expand_sides_menu(items, 0);
1217  }
1218 
1219  if(first_id == "editor-switch-area") {
1221  context_manager_->expand_areas_menu(items, 0);
1222  }
1223 
1224  if(first_id == "editor-pbl") {
1226  }
1227 
1228  if(!items.empty() && items.front()["id"] == "editor-switch-time") {
1230  context_manager_->expand_time_menu(items, 0);
1231  }
1232 
1233  if(first_id == "editor-assign-local-time") {
1235  context_manager_->expand_local_time_menu(items, 0);
1236  }
1237 
1238  if(first_id == "menu-unit-facings") {
1240  auto pos = items.erase(items.begin());
1241  int dir = 0;
1242  std::generate_n(std::inserter<std::vector<config>>(items, pos), static_cast<int>(map_location::direction::indeterminate), [&dir]() -> config {
1244  });
1245  }
1246 
1247  if(first_id == "editor-playlist") {
1249  auto pos = items.erase(items.begin());
1250  std::transform(music_tracks_.begin(), music_tracks_.end(), std::inserter<std::vector<config>>(items, pos), [](const sound::music_track& track) -> config {
1251  return config {"label", track.title().empty() ? track.id() : track.title()};
1252  });
1253  }
1254 
1255  if(first_id == "editor-assign-schedule") {
1257  auto pos = items.erase(items.begin());
1258  std::transform(tods_.begin(), tods_.end(), std::inserter<std::vector<config>>(items, pos), [](const tods_map::value_type& tod) -> config {
1259  return config {"label", tod.second.first};
1260  });
1261  }
1262 
1263  if(first_id == "editor-assign-local-schedule") {
1265  auto pos = items.erase(items.begin());
1266  std::transform(tods_.begin(), tods_.end(), std::inserter<std::vector<config>>(items, pos), [](const tods_map::value_type& tod) -> config {
1267  return config {"label", tod.second.first};
1268  });
1269  }
1270 
1271  command_executor::show_menu(items, xloc, yloc, context_menu, disp);
1272 }
1273 
1275 {
1276  gui_->clear_help_string();
1277  gui2::dialogs::preferences_dialog::display();
1278 
1279  gui_->queue_rerender();
1280 }
1281 
1283 {
1284  prefs::get().set_grid(!prefs::get().grid());
1285  gui_->invalidate_all();
1286 }
1287 
1289 {
1290  map_location loc = gui_->mouseover_hex();
1291  const unit_map & units = get_current_map_context().units();
1292  const unit_map::const_unit_iterator un = units.find(loc);
1293  if(un != units.end()) {
1294  help::show_unit_help(un->type_id(), un->type().show_variations_in_help(), false);
1295  } else {
1296  help::show_help("..units");
1297  }
1298 }
1299 
1300 
1302 {
1303  if (!get_current_map_context().map().selection().empty()) {
1304  context_manager_->get_clipboard() = map_fragment(get_current_map_context().map(), get_current_map_context().map().selection());
1305  context_manager_->get_clipboard().center_by_mass();
1306  }
1307 }
1308 
1310 {
1311  map_location loc = gui_->mouseover_hex();
1312  unit_map& units = get_current_map_context().units();
1313  const unit_map::unit_iterator& un = units.find(loc);
1314 
1315  const std::string title(N_("Change Unit ID"));
1316  const std::string label(N_("ID:"));
1317 
1318  if(un != units.end()) {
1319  std::string id = un->id();
1320  if (gui2::dialogs::edit_text::execute(title, label, id)) {
1321  un->set_id(id);
1322  }
1323  }
1324 }
1325 
1327 {
1328  map_location loc = gui_->mouseover_hex();
1329  unit_map& units = get_current_map_context().units();
1330  const unit_map::unit_iterator& un = units.find(loc);
1331 
1332  const std::string title(N_("Rename Unit"));
1333  const std::string label(N_("Name:"));
1334 
1335  if(un != units.end()) {
1336  std::string name = un->name();
1337  if(gui2::dialogs::edit_text::execute(title, label, name)) {
1338  //TODO we may not want a translated name here.
1339  un->set_name(name);
1340  }
1341  }
1342 }
1343 
1345 {
1347 }
1348 
1350 {
1351  copy_selection();
1353 }
1354 
1356 {
1357  const std::set<map_location>& area = get_current_map_context().map().selection();
1359 }
1360 
1362 {
1363  const std::set<map_location>& area = get_current_map_context().map().selection();
1365 }
1366 
1368 {
1369  std::stringstream ssx, ssy;
1370  std::set<map_location>::const_iterator i = get_current_map_context().map().selection().begin();
1371  if (i != get_current_map_context().map().selection().end()) {
1372  ssx << "x = " << i->wml_x();
1373  ssy << "y = " << i->wml_y();
1374  ++i;
1375  while (i != get_current_map_context().map().selection().end()) {
1376  ssx << ", " << i->wml_x();
1377  ssy << ", " << i->wml_y();
1378  ++i;
1379  }
1380  ssx << "\n" << ssy.str() << "\n";
1382  }
1383 }
1384 
1385 void editor_controller::perform_delete(std::unique_ptr<editor_action> action)
1386 {
1387  if (action) {
1389  }
1390 }
1391 
1392 void editor_controller::perform_refresh_delete(std::unique_ptr<editor_action> action, bool drag_part /* =false */)
1393 {
1394  if (action) {
1395  context_manager_->perform_refresh(*action, drag_part);
1396  }
1397 }
1398 
1400 {
1402  context_manager_->refresh_all();
1403 }
1404 
1406 {
1407  set_button_state();
1408  toolkit_->adjust_size();
1410 }
1411 
1413 {
1415  context_manager_->refresh_after_action();
1416 }
1417 
1419 {
1421  context_manager_->refresh_after_action();
1422 }
1423 
1424 void editor_controller::mouse_motion(int x, int y, const bool /*browse*/,
1425  bool update, map_location /*new_loc*/)
1426 {
1427  if (mouse_handler_base::mouse_motion_default(x, y, update)) return;
1428  map_location hex_clicked = gui().hex_clicked_on(x, y);
1429  if (get_current_map_context().map().on_board_with_border(drag_from_hex_) && is_dragging()) {
1430  std::unique_ptr<editor_action> a;
1431  bool partial = false;
1432  // last_undo is a non-owning pointer. Although it could have other uses, it seems to be
1433  // mainly (only?) used for printing debugging information.
1434  auto last_undo = get_current_map_context().last_undo_action();
1435  if (dragging_left_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(1)) != 0) {
1436  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
1437  a = get_mouse_action().drag_left(*gui_, x, y, partial, last_undo);
1438  } else if (dragging_right_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(3)) != 0) {
1439  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
1440  a = get_mouse_action().drag_right(*gui_, x, y, partial, last_undo);
1441  }
1442  //Partial means that the mouse action has modified the
1443  //last undo action and the controller shouldn't add
1444  //anything to the undo stack (hence a different perform_ call)
1445  if (a != nullptr) {
1446  if (partial) {
1448  } else {
1450  }
1451  context_manager_->refresh_after_action(true);
1452  }
1453  } else {
1454  get_mouse_action().move(*gui_, hex_clicked);
1455  }
1456  gui().highlight_hex(hex_clicked);
1457 }
1458 
1459 void editor_controller::touch_motion(int /* x */, int /* y */, const bool /* browse */, bool /* update */, map_location /* new_loc */)
1460 {
1461  // Not implemented at all. Sorry, it's a very low priority for iOS port.
1462 }
1463 
1465 {
1466  return get_current_map_context().map().on_board_with_border(gui().hex_clicked_on(x,y));
1467 }
1468 
1469 bool editor_controller::right_click_show_menu(int /*x*/, int /*y*/, const bool /*browse*/)
1470 {
1472 }
1473 
1474 bool editor_controller::left_click(int x, int y, const bool browse)
1475 {
1476  toolkit_->clear_mouseover_overlay();
1477  if (mouse_handler_base::left_click(x, y, browse))
1478  return true;
1479 
1480  LOG_ED << "Left click, after generic handling";
1481  map_location hex_clicked = gui().hex_clicked_on(x, y);
1482  if (!get_current_map_context().map().on_board_with_border(hex_clicked))
1483  return true;
1484 
1485  LOG_ED << "Left click action " << hex_clicked;
1486  auto a = get_mouse_action().click_left(*gui_, x, y);
1487  if(a) {
1488  perform_refresh_delete(std::move(a), true);
1489  set_button_state();
1490  }
1491 
1492  return false;
1493 }
1494 
1495 void editor_controller::left_drag_end(int x, int y, const bool /*browse*/)
1496 {
1497  auto a = get_mouse_action().drag_end_left(*gui_, x, y);
1498  perform_delete(std::move(a));
1499 }
1500 
1501 void editor_controller::left_mouse_up(int x, int y, const bool /*browse*/)
1502 {
1503  auto a = get_mouse_action().up_left(*gui_, x, y);
1504  if(a) {
1505  perform_delete(std::move(a));
1506  set_button_state();
1507  }
1508  toolkit_->set_mouseover_overlay();
1509  context_manager_->refresh_after_action();
1510 }
1511 
1512 bool editor_controller::right_click(int x, int y, const bool browse)
1513 {
1514  toolkit_->clear_mouseover_overlay();
1515  if (mouse_handler_base::right_click(x, y, browse)) return true;
1516  LOG_ED << "Right click, after generic handling";
1517  map_location hex_clicked = gui().hex_clicked_on(x, y);
1518  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return true;
1519  LOG_ED << "Right click action " << hex_clicked;
1520  auto a = get_mouse_action().click_right(*gui_, x, y);
1521  if(a) {
1522  perform_refresh_delete(std::move(a), true);
1523  set_button_state();
1524  }
1525  return false;
1526 }
1527 
1528 void editor_controller::right_drag_end(int x, int y, const bool /*browse*/)
1529 {
1530  auto a = get_mouse_action().drag_end_right(*gui_, x, y);
1531  perform_delete(std::move(a));
1532 }
1533 
1534 void editor_controller::right_mouse_up(int x, int y, const bool browse)
1535 {
1536  // Call base method to handle context menus.
1537  mouse_handler_base::right_mouse_up(x, y, browse);
1538 
1539  auto a = get_mouse_action().up_right(*gui_, x, y);
1540  if(a) {
1541  perform_delete(std::move(a));
1542  set_button_state();
1543  }
1544  toolkit_->set_mouseover_overlay();
1545  context_manager_->refresh_after_action();
1546 }
1547 
1549 {
1550  const map_location& loc = gui().mouseover_hex();
1551  if (get_current_map_context().map().on_board(loc) == false)
1552  return;
1553 
1556 }
1557 
1558 void editor_controller::process_keyup_event(const SDL_Event& event)
1559 {
1560  auto a = get_mouse_action().key_event(gui(), event);
1561  perform_refresh_delete(std::move(a));
1562  toolkit_->set_mouseover_overlay();
1563 }
1564 
1566  return this;
1567 }
1568 
1570 {
1572 }
1573 
1575 {
1577 }
1578 
1580 {
1582 }
1583 
1585 {
1587 }
1588 
1590 {
1591  return toolkit_->get_palette_manager()->active_palette().action_pressed();
1592 }
1593 
1594 } //end namespace editor
Editor action classes.
Editor action classes.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
child_itors child_range(config_key_type key)
Definition: config.cpp:272
void set_scroll_up(bool on)
void set_scroll_left(bool on)
virtual bool in_context_menu(const hotkey::ui_command &cmd) const
void set_scroll_right(bool on)
const game_config_view & game_config_
void set_scroll_down(bool on)
virtual void play_slice()
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition: display.hpp:97
void toggle_debug_flag(DEBUG_FLAG flag)
Definition: display.hpp:947
virtual void highlight_hex(map_location hex)
Definition: display.cpp:1484
@ DEBUG_COORDINATES
Overlays x,y coords on tiles.
Definition: display.hpp:919
@ DEBUG_NUM_BITMAPS
Overlays number of bitmaps on tiles.
Definition: display.hpp:925
@ DEBUG_TERRAIN_CODES
Overlays terrain codes on tiles.
Definition: display.hpp:922
void invalidate_all()
Function to invalidate all tiles.
Definition: display.cpp:3080
surface screenshot(bool map_screenshot=false)
Capture a (map-)screenshot into a surface.
Definition: display.cpp:725
void queue_rerender()
Marks everything for rendering including all tiles and sidebar.
Definition: display.cpp:2261
void set_debug_flag(DEBUG_FLAG flag, bool value)
Definition: display.hpp:942
const map_location & mouseover_hex() const
Definition: display.hpp:310
map_location hex_clicked_on(int x, int y) const
given x,y co-ordinates of an onscreen pixel, will return the location of the hex that this pixel corr...
Definition: display.cpp:538
Container action wrapping several actions into one.
Definition: action.hpp:88
Paint the same terrain on a number of locations on the map.
Definition: action.hpp:266
Randomize terrain in an area.
Definition: action.hpp:399
The editor_controller class contains the mouse and keyboard event handling routines for the editor.
const std::unique_ptr< context_manager > context_manager_
void preferences() override
Show the preferences dialog.
void refresh_image_cache()
Reload images.
void right_drag_end(int x, int y, const bool browse) override
Called whenever the right mouse drag has "ended".
void unit_editor_dialog()
Show Unit Editor dialog.
bool can_execute_command(const hotkey::ui_command &command) const override
command_executor override
bool quit_confirm()
Show a quit confirmation dialog and returns true if the user pressed 'yes'.
void scroll_up(bool on) override
Handle hotkeys to scroll map.
void cut_selection()
Cut the selection from the current map to the clipboard.
void display_redraw_callback(display &)
Callback function passed to display to be called on queue_rerender.
std::unique_ptr< font::floating_label_context > floating_label_manager_
void show_menu(const std::vector< config > &items_arg, int xloc, int yloc, bool context_menu, display &disp) override
controller_base override
void undo() override
Undos an action in the current map context.
void left_mouse_up(int x, int y, const bool browse) override
Called when the left mouse button is up.
bool left_click(int x, int y, const bool browse) override
Overridden in derived classes, called on a left click (mousedown).
bool allow_mouse_wheel_scroll(int x, int y) override
Derived classes can override this to disable mousewheel scrolling under some circumstances,...
void touch_motion(int x, int y, const bool browse, bool update=false, map_location new_loc=map_location::null_location()) override
virtual std::vector< std::string > additional_actions_pressed() override
void perform_refresh_delete(std::unique_ptr< editor_action > action, bool drag_part=false)
Peform an action on the current map_context, then refresh the display and delete the pointer.
void init_tods(const game_config_view &game_config)
init the available time-of-day settings
bool initialize_addon()
Initialize an addon if the addon id is empty.
const mouse_action & get_mouse_action() const
Get the current mouse action.
map_context & get_current_map_context() const
std::unique_ptr< editor_toolkit > toolkit_
void scroll_right(bool on) override
void init_music(const game_config_view &game_config)
init background music for the editor
const std::unique_ptr< editor_display > gui_
The display object used and owned by the editor.
bool do_execute_command(const hotkey::ui_command &command, bool press=true, bool release=false) override
command_executor override
void export_selection_coords()
Export the WML-compatible list of selected tiles to the system clipboard.
void redo() override
Redos an action in the current map context.
editor_display & gui() override
Reference to the used display objects.
void update_map_schedule(std::vector< time_of_day > schedule)
Updates schedule and the map display.
hotkey::ACTION_STATE get_action_state(const hotkey::ui_command &command) const override
command_executor override
void perform_delete(std::unique_ptr< editor_action > action)
Perform an action, then delete the action object.
void right_mouse_up(int x, int y, const bool browse) override
Called when the right mouse button is up.
virtual hotkey::command_executor * get_hotkey_command_executor() override
Optionally get a command executor to handle context menu events.
void mouse_motion(int x, int y, const bool browse, bool update, map_location new_loc=map_location::null_location()) override
Called when a mouse motion event takes place.
EXIT_STATUS main_loop()
Editor main loop.
editor_controller(const editor_controller &)=delete
void custom_tods_dialog()
Display the settings dialog, used to control e.g.
void do_screenshot(const std::string &screenshot_filename="map_screenshot.png")
Takes a screenshot.
void toggle_grid() override
Grid toggle.
void scroll_left(bool on) override
bool right_click(int x, int y, const bool browse) override
Overridden in derived classes, called on a right click (mousedown).
void save_area()
Save the current selection to the active area.
void process_keyup_event(const SDL_Event &event) override
Process keyup (always).
void copy_selection()
Copy the selection on the current map to the clipboard.
void init_gui()
init the display object and general set-up
std::unique_ptr< help::help_manager > help_manager_
std::vector< sound::music_track > music_tracks_
bool right_click_show_menu(int x, int y, const bool browse) override
Called in the default right_click when the context menu is about to be shown, can be used for preproc...
static std::string current_addon_id_
void add_area()
Add a new area to the current context, filled with the selection if any.
void scroll_down(bool on) override
void left_drag_end(int x, int y, const bool browse) override
Called whenever the left mouse drag has "ended".
bool do_quit_
Quit main loop flag.
void save_map() override
Save the map, open dialog if not named yet.
void set_help_string_enabled(bool value)
Sets whether the help text should be shown.
bool everything_selected() const
Definition: editor_map.cpp:207
const std::set< map_location > & selection() const
Return the selection set.
Definition: editor_map.hpp:148
List of starting locations and location ids.
const std::string & selected_item() const
Return the currently selected item.
void save_area(const std::set< map_location > &area)
void new_area(const std::set< map_location > &area)
void perform_partial_action(const editor_action &action)
Performs a partial action, assumes that the top undo action has been modified to maintain coherent st...
void remove_side()
removes the last side from the scenario
void set_active_area(int index)
bool modified() const
virtual const unit_map & units() const override
Const units accessor.
void set_local_starting_time(int time)
int get_active_area() const
void new_side()
Adds a new side to the map.
editor_action * last_undo_action()
void redo()
Re-does a previously undid action, and puts it back in the undo stack.
void set_starting_time(int time)
bool select_area(int index)
Select the nth tod area.
bool can_redo() const
bool can_undo() const
void perform_action(const editor_action &action)
Performs an action (thus modifying the map).
void undo()
Un-does the last action, and puts it in the redo stack for a possible redo.
void replace_schedule(const std::vector< time_of_day > &schedule)
bool is_in_playlist(std::string track_id)
void remove_area(int index)
void replace_local_schedule(const std::vector< time_of_day > &schedule)
Replace the [time]s of the currently active area.
const tod_manager * get_time_manager() const
void partial_undo()
Un-does a single step from a undo action chain.
virtual const editor_map & map() const override
Const map accessor.
void add_to_playlist(const sound::music_track &track)
const std::string & get_filename() const
void set_starting_position_labels(display &disp)
map_labels & get_labels()
virtual const std::vector< team > & teams() const override
Const teams accessor.
bool is_pure_map() const
void save_schedule(const std::string &schedule_id, const std::string &schedule_name)
Save custom time of day schedule in the utils directory.
A map fragment – a collection of locations and information abut them.
virtual std::unique_ptr< editor_action > click_left(editor_display &disp, int x, int y)=0
A click, possibly the beginning of a drag.
virtual std::unique_ptr< editor_action > click_right(editor_display &disp, int x, int y)=0
A click, possibly the beginning of a drag.
virtual std::unique_ptr< editor_action > drag_end_right(editor_display &disp, int x, int y)
virtual bool has_context_menu() const
virtual std::unique_ptr< editor_action > up_left(editor_display &disp, int x, int y)
virtual void move(editor_display &disp, const map_location &hex)
Mouse move (not a drag).
virtual std::unique_ptr< editor_action > up_right(editor_display &disp, int x, int y)
virtual std::unique_ptr< editor_action > key_event(editor_display &disp, const SDL_Event &e)
Function called by the controller on a key event for the current mouse action.
virtual std::unique_ptr< editor_action > drag_left(editor_display &disp, int x, int y, bool &partial, editor_action *last_undo)
Drag operation.
virtual std::unique_ptr< editor_action > drag_right(editor_display &disp, int x, int y, bool &partial, editor_action *last_undo)
Drag operation.
virtual bool supports_brushes() const
Whether we need the brush bar, is used to grey it out.
virtual std::unique_ptr< editor_action > drag_end_left(editor_display &disp, int x, int y)
The end of dragging.
bool dragging_right_
RMB drag init flag.
bool dragging_left_
LMB drag init flag.
map_location drag_from_hex_
Drag start or mouse-down map location.
A class grating read only view to a vector of config objects, viewed as one config with all children ...
bool on_board_with_border(const map_location &loc) const
Definition: map.cpp:390
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition: map.cpp:98
const std::vector< time_of_day > get_schedule()
Return current schedule.
Definition: custom_tod.cpp:358
void register_callback(std::function< void(std::vector< time_of_day >)>)
Register callback for update.
Definition: custom_tod.cpp:364
Dialog that allows user to create custom unit types.
Definition: edit_unit.hpp:37
void write()
Write the cfg file.
Definition: edit_unit.cpp:1038
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.
Definition: file_dialog.hpp:59
std::string path() const
Gets the current file selection.
@ auto_close
Enables auto close.
Definition: message.hpp:71
bool show(const unsigned auto_close_time=0)
Shows the window.
virtual bool do_execute_command(const hotkey::ui_command &command, bool press=true, bool release=false)
void recalculate_labels()
Definition: label.cpp:245
static prefs & get()
Implements a quit confirmation dialog.
static bool show_prompt(const std::string &message)
static bool quit()
Shows the quit confirmation if needed.
static void quit_to_desktop()
Internal representation of music tracks.
const std::string & file_path() const
const std::string & id() 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
int get_current_time(const map_location &loc=map_location::null_location()) const
int get_current_area_time(int index) const
Container associating units to locations.
Definition: map.hpp:98
unit_iterator end()
Definition: map.hpp:428
bool empty() const
Definition: map.hpp:445
unit_iterator find(std::size_t id)
Definition: map.cpp:302
Editor action classes.
#define LOG_ED
#define ERR_ED
#define SCOPE_ED
#define WRN_ED
std::size_t i
Definition: function.cpp:1028
static auto & dummy
#define N_(String)
Definition: gettext.hpp:101
static std::string _(const char *str)
Definition: gettext.hpp:93
std::string label
What to show in the filter's drop-down list.
Definition: manager.cpp:200
Contains functions for cleanly handling SDL input.
static bool timestamp
Definition: log.cpp:61
auto format_local_timestamp(const std::chrono::system_clock::time_point &time, std::string_view format="%F %T")
Definition: chrono.hpp:61
CURSOR_TYPE get()
Definition: cursor.cpp:216
@ NORMAL
Definition: cursor.hpp:28
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:176
void copy_to_clipboard(const std::string &text)
Copies text to the clipboard.
Definition: clipboard.cpp:27
bool open_object([[maybe_unused]] const std::string &path_or_url)
Definition: open.cpp:46
constexpr bool open_object_is_supported()
Returns whether open_object() is supported/implemented for the current platform.
Definition: open.hpp:54
static void update()
Manage the empty-palette in the editor.
Definition: action.cpp:31
@ EXIT_ERROR
Definition: editor_main.hpp:27
@ EXIT_NORMAL
Definition: editor_main.hpp:24
@ EXIT_RELOAD_DATA
Definition: editor_main.hpp:26
const t_translation::terrain_code & get_selected_bg_terrain()
std::string initialize_addon()
Definition: editor_main.cpp:32
bool is_cfg(const std::string &filename)
Returns true if the file ends with the wmlfile extension.
bool is_map(const std::string &filename)
Returns true if the file ends with the mapfile extension.
std::string get_current_editor_dir(const std::string &addon_id)
Game configuration data as global variables.
Definition: build_info.cpp:61
void show_unit_list(display &gui)
Definition: unit_list.cpp:184
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.
Definition: message.cpp:201
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:148
void show_help(const std::string &show_topic)
Open the help browser, show topic with id show_topic.
Definition: help.cpp:140
void show_terrain_description(const terrain_type &t)
Definition: help.cpp:77
void show_unit_help(const std::string &show_topic, bool has_variations, bool hidden)
Open the help browser, show unit with id unit_id.
Definition: help.cpp:151
Keyboard shortcuts for game actions.
const hotkey_command & get_hotkey_command(const std::string &command)
returns the hotkey_command with the given name
@ HOTKEY_EDITOR_TOOL_VILLAGE
@ HOTKEY_MINIMAP_DRAW_VILLAGES
@ HOTKEY_EDITOR_BRUSH_NW_SE
@ HOTKEY_EDITOR_REFRESH
@ HOTKEY_FULLSCREEN
@ HOTKEY_EDITOR_SELECT_NONE
@ HOTKEY_ANIMATE_MAP
@ HOTKEY_SCREENSHOT
@ HOTKEY_EDITOR_CLIPBOARD_ROTATE_CCW
@ HOTKEY_MOUSE_SCROLL
@ HOTKEY_EDITOR_PALETTE_GROUPS
@ HOTKEY_TERRAIN_DESCRIPTION
@ HOTKEY_EDITOR_PALETTE_UPSCROLL
@ HOTKEY_EDITOR_SIDE_REMOVE
@ HOTKEY_EDITOR_BRUSH_NEXT
@ HOTKEY_EDITOR_TOOL_LABEL
@ HOTKEY_EDITOR_CLIPBOARD_ROTATE_CW
@ HOTKEY_EDITOR_BRUSH_3
@ HOTKEY_SCROLL_LEFT
@ HOTKEY_EDITOR_CLIPBOARD_PASTE
@ HOTKEY_EDITOR_PARTIAL_UNDO
@ HOTKEY_EDITOR_UNIT_TOGGLE_CANRECRUIT
@ HOTKEY_EDITOR_PALETTE_ITEM_SWAP
@ HOTKEY_EDITOR_TOOL_PAINT
@ HOTKEY_EDITOR_MAP_CLOSE
@ HOTKEY_EDITOR_MAP_GENERATE
@ HOTKEY_EDITOR_SELECTION_FLIP
@ HOTKEY_EDITOR_SCHEDULE
@ HOTKEY_EDITOR_TOOL_FILL
@ HOTKEY_EDITOR_SCENARIO_SAVE_AS
@ HOTKEY_EDITOR_PLAYLIST
@ HOTKEY_EDITOR_MAP_SAVE_AS
@ HOTKEY_UNIT_DESCRIPTION
@ HOTKEY_SCROLL_RIGHT
@ HOTKEY_EDITOR_SELECT_ALL
@ HOTKEY_EDITOR_DRAW_COORDINATES
@ HOTKEY_EDITOR_TOOL_NEXT
@ HOTKEY_EDITOR_SELECTION_EXPORT
@ HOTKEY_EDITOR_PARTIAL_UPDATE_TRANSITIONS
@ HOTKEY_EDITOR_MAP_CREATE_MASK_TO
@ HOTKEY_TOGGLE_GRID
@ HOTKEY_EDITOR_SELECTION_CUT
@ HOTKEY_EDITOR_UNIT_CHANGE_ID
@ HOTKEY_MINIMAP_DRAW_TERRAIN
@ HOTKEY_EDITOR_DRAW_NUM_OF_BITMAPS
@ HOTKEY_MAP_SCREENSHOT
@ HOTKEY_EDITOR_AREA_ADD
@ HOTKEY_EDITOR_BRUSH_SW_NE
@ HOTKEY_EDITOR_TOOL_UNIT
@ HOTKEY_QUIT_TO_DESKTOP
@ HOTKEY_EDITOR_HELP_TEXT_SHOWN
@ HOTKEY_EDITOR_CHANGE_ADDON_ID
@ HOTKEY_EDITOR_CUSTOM_TODS
@ HOTKEY_EDITOR_REFRESH_IMAGE_CACHE
@ HOTKEY_EDITOR_SELECTION_FILL
@ HOTKEY_EDITOR_CLIPBOARD_FLIP_VERTICAL
@ HOTKEY_EDITOR_MAP_SAVE_ALL
@ HOTKEY_EDITOR_BRUSH_1
@ HOTKEY_EDITOR_SELECTION_ROTATE
@ HOTKEY_EDITOR_MAP_LOAD
@ HOTKEY_RENAME_UNIT
@ HOTKEY_EDITOR_BRUSH_2
@ HOTKEY_EDITOR_TOOL_STARTING_POSITION
@ HOTKEY_MINIMAP_CODING_TERRAIN
@ HOTKEY_EDITOR_NO_UPDATE_TRANSITIONS
@ HOTKEY_EDITOR_SELECTION_COPY
@ HOTKEY_MINIMAP_DRAW_UNITS
@ HOTKEY_EDITOR_PALETTE_DOWNSCROLL
@ HOTKEY_EDITOR_UNIT_TOGGLE_LOYAL
@ HOTKEY_EDITOR_MAP_APPLY_MASK
@ HOTKEY_EDITOR_LOCAL_TIME
@ HOTKEY_EDITOR_UNIT_FACING
@ HOTKEY_PREFERENCES
@ HOTKEY_STATUS_TABLE
@ HOTKEY_DELETE_UNIT
@ HOTKEY_EDITOR_EDIT_UNIT
@ HOTKEY_EDITOR_SIDE_NEW
@ HOTKEY_EDITOR_SELECTION_RANDOMIZE
@ HOTKEY_EDITOR_SCENARIO_NEW
@ HOTKEY_EDITOR_MAP_SWITCH
@ HOTKEY_EDITOR_SELECT_INVERSE
@ HOTKEY_EDITOR_TOGGLE_TRANSITIONS
@ HOTKEY_UNIT_LIST
@ HOTKEY_SCROLL_DOWN
@ HOTKEY_EDITOR_AUTO_UPDATE_TRANSITIONS
@ HOTKEY_ZOOM_DEFAULT
@ HOTKEY_EDITOR_AREA_RENAME
@ HOTKEY_EDITOR_MAP_RESIZE
@ HOTKEY_SCROLL_UP
@ HOTKEY_EDITOR_DRAW_TERRAIN_CODES
@ HOTKEY_EDITOR_AREA_REMOVE
@ HOTKEY_QUIT_GAME
@ HOTKEY_EDITOR_UPDATE_TRANSITIONS
@ HOTKEY_EDITOR_TOOL_SELECT
@ HOTKEY_EDITOR_MAP_NEW
@ HOTKEY_EDITOR_MAP_SAVE
@ HOTKEY_EDITOR_AREA_SAVE
@ HOTKEY_EDITOR_REMOVE_LOCATION
@ HOTKEY_EDITOR_SIDE_EDIT
@ HOTKEY_EDITOR_SELECT_ADDON
@ HOTKEY_EDITOR_TOOL_ITEM
@ TITLE_SCREEN__RELOAD_WML
@ HOTKEY_EDITOR_UNIT_TOGGLE_RENAMEABLE
@ HOTKEY_EDITOR_SCENARIO_EDIT
@ HOTKEY_EDITOR_OPEN_ADDON
@ HOTKEY_EDITOR_MAP_REVERT
@ HOTKEY_EDITOR_CLIPBOARD_FLIP_HORIZONTAL
@ HOTKEY_MINIMAP_CODING_UNIT
void flush_cache()
Purges all image caches.
Definition: picture.cpp:200
save_result save_image(const locator &i_locator, const std::string &filename)
Definition: picture.cpp:884
int show_menu(lua_State *L)
Displays a popup menu at the current mouse position Best used from a [set_menu_item],...
Definition: lua_gui2.cpp:188
Unit and team statistics.
::tod_manager * tod_manager
Definition: resources.cpp:29
game_classification * classification
Definition: resources.cpp:34
filter_context * filter_con
Definition: resources.cpp:23
uint32_t get_mouse_button_mask()
Returns the current mouse button mask.
Definition: input.cpp:49
void play_music_once(const std::string &file)
Definition: sound.cpp:603
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:70
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:85
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
Desktop environment interaction functions.
@ partial
There are still moves and/or attacks possible, but the unit doesn't fit in the "unmoved" status.
structure which will hide all current floating labels, and cause floating labels instantiated after i...
The help implementation caches data parsed from the game_config.
Definition: help.hpp:39
Used as the main paramneter for can_execute_command/do_execute_command These functions are used to ex...
hotkey::HOTKEY_COMMAND hotkey_command
The hotkey::HOTKEY_COMMAND associated with this action, HOTKEY_NULL for actions that don't allow hotk...
int index
When this action was the result of a menu click, this is the index of the clicked item in the menu.
Encapsulates the map of the game.
Definition: location.hpp:45
bool valid() const
Definition: location.hpp:110
direction
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:47
static std::string write_translated_direction(direction dir)
Definition: location.cpp:175
Helper class, don't construct this directly.
mock_char c
Add a special kind of assert to validate whether the input from WML doesn't contain any problems that...
#define e
#define b