The Battle for Wesnoth  1.19.2+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 
59 #include <functional>
60 
61 namespace {
62 static std::vector<std::string> saved_windows_;
63 }
64 
65 namespace editor {
66 
68 
70  : controller_base()
71  , mouse_handler_base()
72  , quit_confirmation(std::bind(&editor_controller::quit_confirm, this))
73  , active_menu_(editor::MAP)
74  , reports_(new reports())
75  , gui_(new editor_display(*this, *reports_))
76  , tods_()
77  , context_manager_(new context_manager(*gui_.get(), game_config_, clear_id ? "" : editor_controller::current_addon_id_))
78  , toolkit_(nullptr)
79  , tooltip_manager_()
80  , floating_label_manager_(nullptr)
81  , help_manager_(nullptr)
82  , do_quit_(false)
83  , quit_mode_(EXIT_ERROR)
84  , music_tracks_()
85 {
86  if(clear_id) {
88  }
89 
90  init_gui();
91  toolkit_.reset(new editor_toolkit(*gui_.get(), key_, game_config_, *context_manager_.get()));
93  context_manager_->locs_ = toolkit_->get_palette_manager()->location_palette_.get();
98 
99  gui().queue_rerender();
100 }
101 
103 {
104  gui_->change_display_context(&get_current_map_context());
105  gui_->add_redraw_observer(std::bind(&editor_controller::display_redraw_callback, this, std::placeholders::_1));
107  gui().set_debug_flag(display::DEBUG_COORDINATES, prefs::get().editor_draw_hex_coordinates());
108  gui().set_debug_flag(display::DEBUG_TERRAIN_CODES, prefs::get().editor_draw_terrain_codes());
109  gui().set_debug_flag(display::DEBUG_NUM_BITMAPS, prefs::get().editor_draw_num_of_bitmaps());
110 // halo_manager_.reset(new halo::manager(*gui_));
111 // resources::halo = halo_manager_.get();
112 // ^ These lines no longer necessary, the gui owns its halo manager.
113 // TODO: Should the editor map contexts actually own the halo manager and swap them in and out from the gui?
114 // 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
115 // without deleting it.
116 }
117 
119 {
120  for (const config &schedule : game_config.child_range("editor_times")) {
121 
122  const std::string& schedule_id = schedule["id"];
123  /* Use schedule id as the name if schedule name is empty */
124  const std::string& schedule_name = schedule["name"].empty() ? schedule["id"] : schedule["name"];
125  if (schedule_id.empty()) {
126  ERR_ED << "Missing ID attribute in a TOD Schedule.";
127  continue;
128  }
129 
130  tods_map::iterator times = tods_.find(schedule_id);
131  if (times == tods_.end()) {
132  std::pair<tods_map::iterator, bool> new_times =
133  tods_.emplace(schedule_id, std::pair(schedule_name, std::vector<time_of_day>()));
134  times = new_times.first;
135  } else {
136  ERR_ED << "Duplicate TOD Schedule identifiers.";
137  continue;
138  }
139 
140  for (const config &time : schedule.child_range("time")) {
141  times->second.second.emplace_back(time);
142  }
143 
144  }
145 
146  if (tods_.empty()) {
147  ERR_ED << "No editor time-of-day defined";
148  }
149 }
150 
152 {
153  const std::string tag_name = "editor_music";
154  if (game_config.child_range(tag_name).size() == 0) {
155  ERR_ED << "No editor music defined";
156  }
157  else {
158  for (const config& editor_music : game_config.child_range(tag_name)) {
159  for (const config& music : editor_music.child_range("music")) {
160  sound::music_track track(music);
161  if (track.file_path().empty())
162  WRN_ED << "Music track " << track.id() << " not found.";
163  else
164  music_tracks_.emplace_back(music);
165  }
166  }
167  }
168 }
169 
171 {
172  resources::tod_manager = nullptr;
173  resources::filter_con = nullptr;
174 
175  resources::classification = nullptr;
176 }
177 
179 {
180  try {
181  while (!do_quit_) {
182  play_slice();
183  }
184  } catch (const editor_exception& e) {
185  gui2::show_transient_message(_("Fatal error"), e.what());
186  return EXIT_ERROR;
187  } catch (const wml_exception& e) {
188  e.show();
189  }
190  return quit_mode_;
191 }
192 
194 }
195 
196 void editor_controller::do_screenshot(const std::string& screenshot_filename /* = "map_screenshot.png" */)
197 {
198  try {
199  surface screenshot = gui().screenshot(true);
200  if(!screenshot || image::save_image(screenshot, screenshot_filename) != image::save_result::success) {
201  ERR_ED << "Screenshot creation failed!";
202  }
203  } catch (const wml_exception& e) {
204  e.show();
205  }
206 }
207 
209 {
210  std::string modified;
211  std::size_t amount = context_manager_->modified_maps(modified);
212 
213  std::string message;
214  if (amount == 0) {
215  message = _("Do you really want to quit?");
216  } else if (amount == 1 && get_current_map_context().modified()) {
217  message = _("Do you really want to quit? Changes to this map since the last save will be lost.");
218  } else {
219  message = _("Do you really want to quit? The following maps were modified and all changes since the last save will be lost:");
220  message += "\n" + modified;
221  }
222  return quit_confirmation::show_prompt(message);
223 }
224 
226 {
228  if (unit_dlg.show()) {
229  unit_dlg.write();
230  }
231 }
232 
234 {
235  if (tods_.empty()) {
236  gui2::show_error_message(_("No editor time-of-day found."));
237  return;
238  }
239 
241  std::vector<time_of_day> prev_schedule = manager.times();
242 
243  gui2::dialogs::custom_tod tod_dlg(manager.times(), manager.get_current_time(), current_addon_id_);
244 
245  /* Register callback to the dialog so that the map changes can be
246  * previewed in real time.
247  */
248  std::function<void(std::vector<time_of_day>)> update_func(
249  std::bind(
251  this,
252  std::placeholders::_1));
253  tod_dlg.register_callback(update_func);
254 
255  /* Autogenerate schedule id */
256  std::int64_t current_millis = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
257  std::string sch_id = current_addon_id_+"-schedule";
258  /* Set correct textdomain */
259  t_string sch_name("", "wesnoth-"+current_addon_id_);
260 
261  // TODO : Needs better error handling messages
262  /* Show dialog and update current schedule */
263  if(tod_dlg.show()) {
264  /* Save the new schedule */
265  std::vector<time_of_day> schedule = tod_dlg.get_schedule();
266  if(!gui2::dialogs::tod_new_schedule::execute(sch_id, sch_name)) {
267  /* User pressed Cancel. Restore old schedule */
268  update_map_schedule(prev_schedule);
269  return;
270  }
271 
272  /* In case the ID or Name field is blank and user presses OK */
273  if (sch_id.empty()) {
274  sch_id = current_addon_id_+"-schedule-"+std::to_string(current_millis);
275  } else {
276  /* Check if the id entered is same as any of the existing ids
277  * If so, replace */
278  // TODO : Notify the user if they enter an already existing schedule ID
279  for (auto map_elem : tods_) {
280  if (sch_id == map_elem.first) {
281  sch_id = current_addon_id_+"-schedule-"+std::to_string(current_millis);
282  }
283  }
284  }
285 
286  tods_.emplace(sch_id, std::pair(sch_name, schedule));
288  get_current_map_context().save_schedule(sch_id, sch_name);
289  gui_->update_tod();
290  context_manager_->refresh_all();
291  } else {
292  /* Restore old schedule */
293  update_map_schedule(prev_schedule);
294  }
295 }
296 
297 void editor_controller::update_map_schedule(std::vector<time_of_day> schedule)
298 {
300  gui_->update_tod();
301  context_manager_->refresh_all();
302 }
303 
305 {
306  using namespace hotkey; //reduce hotkey:: clutter
307  int index = cmd.index;
308  switch(cmd.hotkey_command) {
309  case HOTKEY_NULL:
310  if (index >= 0) {
311  unsigned i = static_cast<unsigned>(index);
312 
313  switch (active_menu_) {
314  case editor::MAP:
315  if (i < context_manager_->open_maps()) {
316  return true;
317  }
318  return false;
319  case editor::LOAD_MRU:
320  case editor::PALETTE:
321  case editor::AREA:
322  case editor::ADDON:
323  case editor::SIDE:
324  case editor::TIME:
325  case editor::SCHEDULE:
327  case editor::MUSIC:
328  case editor::LOCAL_TIME:
329  case editor::UNIT_FACING:
330  return true;
331  }
332  }
333  return false;
335  return true;
337  return toolkit_->get_palette_manager()->can_scroll_up();
339  return toolkit_->get_palette_manager()->can_scroll_down();
340  case HOTKEY_ZOOM_IN:
341  return !gui_->zoom_at_max();
342  case HOTKEY_ZOOM_OUT:
343  return !gui_->zoom_at_min();
344  case HOTKEY_ZOOM_DEFAULT:
345  case HOTKEY_FULLSCREEN:
346  case HOTKEY_SCREENSHOT:
348  case HOTKEY_TOGGLE_GRID:
349  case HOTKEY_MOUSE_SCROLL:
350  case HOTKEY_ANIMATE_MAP:
351  case HOTKEY_MUTE:
352  case HOTKEY_PREFERENCES:
353  case HOTKEY_HELP:
354  case HOTKEY_QUIT_GAME:
355  case HOTKEY_SCROLL_UP:
356  case HOTKEY_SCROLL_DOWN:
357  case HOTKEY_SCROLL_LEFT:
358  case HOTKEY_SCROLL_RIGHT:
359  return true; //general hotkeys we can always do
360 
361  case HOTKEY_UNIT_LIST:
362  return !get_current_map_context().units().empty();
363 
364  // TODO Disabling this for now until the functionality can be implemnted.
365  // See the status_table() method
366  case HOTKEY_STATUS_TABLE:
367  //return !get_current_map_context().teams().empty();
368  return false;
369  /////////////////////////////
370 
372  return gui().mouseover_hex().valid();
373 
374  // unit tool related
375  case HOTKEY_DELETE_UNIT:
376  case HOTKEY_RENAME_UNIT:
383  {
384  map_location loc = gui_->mouseover_hex();
385  const unit_map& units = get_current_map_context().units();
386  return (toolkit_->is_mouse_action_set(HOTKEY_EDITOR_TOOL_UNIT) &&
387  units.find(loc) != units.end());
388  }
389 
390  case HOTKEY_UNDO:
393  case HOTKEY_REDO:
395 
402  return true;
403 
404  // Only enable when editing a scenario
409 
410  case HOTKEY_EDITOR_PBL:
414  return true;
415 
419 
422  return !get_current_map_context().teams().empty();
423 
424  // brushes
432 
434  return true;
436  return toolkit_->get_palette_manager()->active_palette().supports_swap();
440  {
441  std::string dummy;
442  return context_manager_->modified_maps(dummy) > 1;
443  }
449  return true;
451  return !get_current_map_context().get_filename().empty()
453 
454  // Tools
455  // Pure map editing tools this can be used all the time.
460  return true;
461  // WWL dependent tools which don't rely on defined sides.
468  return !get_current_map_context().teams().empty();
469 
473  return !get_current_map_context().is_pure_map() &&
475 
477  return !get_current_map_context().is_pure_map() &&
479  && !get_current_map_context().map().selection().empty();
480 
485  return !get_current_map_context().map().selection().empty()
486  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
488  return (get_current_map_context().map().selection().size() > 1
489  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE));
493  return !context_manager_->clipboard_empty();
498  return !context_manager_->clipboard_empty()
499  && toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
502  return !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
504  return !get_current_map_context().map().selection().empty()
506  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
523  return true;
527  return true;
528  default:
529  return false;
530  }
531 }
532 
534 {
535  using namespace hotkey;
536  int index = cmd.index;
537  switch (cmd.hotkey_command) {
538 
540  {
542  get_current_map_context().units().find(gui_->mouseover_hex());
543  return un->loyal() ? ACTION_ON : ACTION_OFF;
544 
545  }
547  {
549  get_current_map_context().units().find(gui_->mouseover_hex());
550  return un->can_recruit() ? ACTION_ON : ACTION_OFF;
551  }
553  {
555  get_current_map_context().units().find(gui_->mouseover_hex());
556  return (!un->unrenamable()) ? ACTION_ON : ACTION_OFF;
557  }
558  //TODO remove hardcoded hotkey names
560  return context_manager_->is_active_transitions_hotkey("editor-auto-update-transitions")
563  return context_manager_->is_active_transitions_hotkey("editor-partial-update-transitions")
566  return context_manager_->is_active_transitions_hotkey("editor-no-update-transitions")
569  return toolkit_->is_active_brush("brush-1") ? ACTION_ON : ACTION_OFF;
571  return toolkit_->is_active_brush("brush-2") ? ACTION_ON : ACTION_OFF;
573  return toolkit_->is_active_brush("brush-3") ? ACTION_ON : ACTION_OFF;
575  return toolkit_->is_active_brush("brush-nw-se") ? ACTION_ON : ACTION_OFF;
577  return toolkit_->is_active_brush("brush-sw-ne") ? ACTION_ON : ACTION_OFF;
578 
579  case HOTKEY_TOGGLE_GRID:
580  return prefs::get().grid() ? ACTION_ON : ACTION_OFF;
585  return get_current_map_context().map().selection().empty() ?
596  return toolkit_->is_mouse_action_set(cmd.hotkey_command) ? ACTION_ON : ACTION_OFF;
598  return gui_->debug_flag_set(display::DEBUG_COORDINATES) ? ACTION_ON : ACTION_OFF;
600  return gui_->debug_flag_set(display::DEBUG_TERRAIN_CODES) ? ACTION_ON : ACTION_OFF;
602  return gui_->debug_flag_set(display::DEBUG_NUM_BITMAPS) ? ACTION_ON : ACTION_OFF;
603 
605  return (prefs::get().minimap_draw_villages()) ? ACTION_ON : ACTION_OFF;
607  return (prefs::get().minimap_movement_coding()) ? ACTION_ON : ACTION_OFF;
609  return (prefs::get().minimap_terrain_coding()) ? ACTION_ON : ACTION_OFF;
611  return (prefs::get().minimap_draw_units()) ? ACTION_ON : ACTION_OFF;
613  return (prefs::get().minimap_draw_terrain()) ? ACTION_ON : ACTION_OFF;
614  case HOTKEY_ZOOM_DEFAULT:
615  return (gui_->get_zoom_factor() == 1.0) ? ACTION_ON : ACTION_OFF;
616 
617  case HOTKEY_NULL:
618  switch (active_menu_) {
619  case editor::MAP:
620  return index == context_manager_->current_context_index()
622  case editor::LOAD_MRU:
623  return ACTION_STATELESS;
624  case editor::PALETTE:
625  return ACTION_STATELESS;
626  case editor::AREA:
629  case editor::ADDON:
630  return ACTION_STATELESS;
631  case editor::SIDE:
632  return static_cast<std::size_t>(index) == gui_->playing_team()
634  case editor::TIME:
637  case editor::LOCAL_TIME:
639  get_current_map_context().get_active_area())
641  case editor::MUSIC:
643  ? ACTION_ON : ACTION_OFF;
644  case editor::SCHEDULE:
645  {
646  tods_map::const_iterator it = tods_.begin();
647  std::advance(it, index);
648  const std::vector<time_of_day>& times1 = it->second.second;
649  const std::vector<time_of_day>& times2 = get_current_map_context().get_time_manager()->times();
650  return (times1 == times2) ? ACTION_SELECTED : ACTION_DESELECTED;
651  }
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  int active_area = get_current_map_context().get_active_area();
658  const std::vector<time_of_day>& times2 = get_current_map_context().get_time_manager()->times(active_area);
659  return (times1 == times2) ? ACTION_SELECTED : ACTION_DESELECTED;
660  }
661  case editor::UNIT_FACING:
662  {
664  assert(un != get_current_map_context().units().end());
665  return un->facing() == index ? ACTION_SELECTED : ACTION_DESELECTED;
666  }
667  }
668  return ACTION_ON;
669  default:
670  return command_executor::get_action_state(cmd);
671  }
672 }
673 
674 bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool press, bool release)
675 {
676  using namespace hotkey;
677  HOTKEY_COMMAND command = cmd.hotkey_command;
678  SCOPE_ED;
679  int index = cmd.index;
680 
681  // nothing here handles release; fall through to base implementation
682  if (!press) {
683  return command_executor::do_execute_command(cmd, press, release);
684  }
685 
686  switch (command) {
687  case HOTKEY_NULL:
688  switch (active_menu_) {
689  case MAP:
690  if (index >= 0) {
691  unsigned i = static_cast<unsigned>(index);
692  if (i < context_manager_->size()) {
693  context_manager_->switch_context(index);
694  toolkit_->hotkey_set_mouse_action(HOTKEY_EDITOR_TOOL_PAINT);
695  return true;
696  }
697  }
698  return false;
699  case LOAD_MRU:
700  if (index >= 0) {
701  context_manager_->load_mru_item(static_cast<unsigned>(index));
702  }
703  return true;
704  case PALETTE:
705  toolkit_->get_palette_manager()->set_group(index);
706  return true;
707  case SIDE:
708  gui_->set_team(index, true);
709  gui_->set_playing_team(index);
710  toolkit_->get_palette_manager()->draw_contents();
711  return true;
712  case AREA:
713  {
715  const std::set<map_location>& area =
717  std::vector<map_location> locs(area.begin(), area.end());
719  gui_->scroll_to_tiles(locs.begin(), locs.end());
720  return true;
721  }
722  case ADDON:
723  return true;
724  case TIME:
725  {
727  gui_->update_tod();
728  return true;
729  }
730  case LOCAL_TIME:
731  {
733  return true;
734  }
735  case MUSIC:
736  {
737  //TODO mark the map as changed
740  std::vector<config> items;
741  items.emplace_back("id", "editor-playlist");
742  std::shared_ptr<gui::button> b = gui_->find_menu_button("menu-playlist");
743  show_menu(items, b->location().x +1, b->location().y + b->height() +1, false, *gui_);
744  return true;
745  }
746  case SCHEDULE:
747  {
748  tods_map::iterator iter = tods_.begin();
749  std::advance(iter, index);
750  get_current_map_context().replace_schedule(iter->second.second);
751  // TODO: test again after the assign-schedule menu is fixed. Should work, though.
752  gui_->update_tod();
753  return true;
754  }
755  case LOCAL_SCHEDULE:
756  {
757  tods_map::iterator iter = tods_.begin();
758  std::advance(iter, index);
759  get_current_map_context().replace_local_schedule(iter->second.second);
760  return true;
761  }
762  case UNIT_FACING:
763  {
765  assert(un != get_current_map_context().units().end());
766  un->set_facing(map_location::DIRECTION(index));
767  un->anim_comp().set_standing();
768  return true;
769  }
770  }
771  return true;
772 
773  //Zoom
774  case HOTKEY_ZOOM_IN:
775  gui_->set_zoom(true);
777  toolkit_->set_mouseover_overlay(*gui_);
778  return true;
779  case HOTKEY_ZOOM_OUT:
780  gui_->set_zoom(false);
782  toolkit_->set_mouseover_overlay(*gui_);
783  return true;
784  case HOTKEY_ZOOM_DEFAULT:
785  gui_->toggle_default_zoom();
787  toolkit_->set_mouseover_overlay(*gui_);
788  return true;
789 
790  //Palette
792  //TODO this code waits for the gui2 dialog to get ready
793  // std::vector< std::pair< std::string, std::string >> blah_items;
794  // toolkit_->get_palette_manager()->active_palette().expand_palette_groups_menu(blah_items);
795  // int selected = 1; //toolkit_->get_palette_manager()->active_palette().get_selected;
796  // gui2::teditor_select_palette_group::execute(selected, blah_items);
797  return true;
799  toolkit_->get_palette_manager()->scroll_up();
800  return true;
802  toolkit_->get_palette_manager()->scroll_down();
803  return true;
804 
805  case HOTKEY_QUIT_GAME:
807  do_quit_ = true;
809  }
810  return true;
813  return true;
815  context_manager_->save_contexts();
816  do_quit_ = true;
818  return true;
821  return true;
824  return true;
826  toolkit_->get_palette_manager()->active_palette().swap();
827  return true;
829  if (dynamic_cast<const editor_action_chain*>(get_current_map_context().last_undo_action()) != nullptr) {
831  context_manager_->refresh_after_action();
832  } else {
833  undo();
834  }
835  return true;
836 
837  //Tool Selection
846  toolkit_->hotkey_set_mouse_action(command);
847  return true;
848 
849  case HOTKEY_EDITOR_PBL:
851 
852  if(!current_addon_id_.empty()) {
853  context_manager_->edit_pbl();
854  }
855  return true;
856 
859 
860  if(!current_addon_id_.empty()) {
861  context_manager_->change_addon_id();
862  }
863  return true;
864 
867  context_manager_->set_addon_id(current_addon_id_);
868  return true;
869 
871  {
873 
875 
876  dlg.set_title(_("Add-on Files"))
878 
879  if (dlg.show()) {
880  std::string filepath = dlg.path();
881  if (filesystem::is_map(filepath) || filesystem::is_cfg(filepath)) {
882  // Open map or scenario
883  context_manager_->load_map(filepath, true);
884  } else {
885  // Open file using OS application for that format
887  desktop::open_object(filepath);
888  } else {
889  gui2::show_message("", _("Opening files is not supported, contact your packager"), gui2::dialogs::message::auto_close);
890  }
891  }
892  }
893 
894  return true;
895  }
896 
898  add_area();
899  return true;
900 
902  change_unit_id();
903  return true;
904 
905  return true;
907  {
908  map_location loc = gui_->mouseover_hex();
910  bool unrenamable = un->unrenamable();
911  un->set_unrenamable(!unrenamable);
912  }
913  return true;
915  {
916  map_location loc = gui_->mouseover_hex();
918  bool canrecruit = un->can_recruit();
919  un->set_can_recruit(!canrecruit);
920  un->anim_comp().set_standing();
921  }
922  return true;
924  {
925  map_location loc = gui_->mouseover_hex();
927  bool loyal = un->loyal();
928  un->set_loyal(!loyal);
929  }
930  return true;
931  case HOTKEY_DELETE_UNIT:
932  {
933  map_location loc = gui_->mouseover_hex();
934  perform_delete(std::make_unique<editor_action_unit_delete>(loc));
935  }
936  return true;
937  case HOTKEY_EDITOR_CLIPBOARD_PASTE: //paste is somewhat different as it might be "one action then revert to previous mode"
938  toolkit_->hotkey_set_mouse_action(command);
939  return true;
940 
941  //Clipboard
943  context_manager_->get_clipboard().rotate_60_cw();
944  toolkit_->update_mouse_action_highlights();
945  return true;
947  context_manager_->get_clipboard().rotate_60_ccw();
948  toolkit_->update_mouse_action_highlights();
949  return true;
951  context_manager_->get_clipboard().flip_horizontal();
952  toolkit_->update_mouse_action_highlights();
953  return true;
955  context_manager_->get_clipboard().flip_vertical();
956  toolkit_->update_mouse_action_highlights();
957  return true;
958 
959  //Brushes
961  toolkit_->cycle_brush();
962  return true;
964  toolkit_->set_brush("brush-1");
965  return true;
967  toolkit_->set_brush("brush-2");
968  return true;
970  toolkit_->set_brush("brush-3");
971  return true;
973  toolkit_->set_brush("brush-nw-se");
974  return true;
976  toolkit_->set_brush("brush-sw-ne");
977  return true;
978 
980  copy_selection();
981  return true;
983  cut_selection();
984  return true;
986  context_manager_->rename_area_dialog();
987  return true;
989  save_area();
990  return true;
993  return true;
995  if(!get_current_map_context().map().everything_selected()) {
996  context_manager_->perform_refresh(editor_action_select_all());
997  return true;
998  }
999  [[fallthrough]];
1001  context_manager_->perform_refresh(editor_action_select_inverse());
1002  return true;
1004  context_manager_->perform_refresh(editor_action_select_none());
1005  return true;
1007  context_manager_->fill_selection();
1008  return true;
1011  get_current_map_context().map().selection()));
1012  return true;
1013 
1015  context_manager_->edit_scenario_dialog();
1016  return true;
1017 
1020  get_current_map_context().get_active_area());
1021  return true;
1022 
1023  // map specific
1025  context_manager_->close_current_context();
1026  // Copy behaviour from when switching windows to always reset the active tool to the Paint Tool
1027  // This avoids the situation of having a scenario-specific tool active in a map context which can cause a crash if used
1028  // Not elegant but at least avoids a potential crash and is consistent with existing behaviour
1029  toolkit_->hotkey_set_mouse_action(HOTKEY_EDITOR_TOOL_PAINT);
1030  return true;
1032  context_manager_->load_map_dialog();
1033  return true;
1035  context_manager_->revert_map();
1036  return true;
1037  case HOTKEY_EDITOR_MAP_NEW:
1038  context_manager_->new_map_dialog();
1039  return true;
1042 
1043  if(!current_addon_id_.empty()) {
1044  context_manager_->new_scenario_dialog();
1045  }
1046  return true;
1048  save_map();
1049  return true;
1051  context_manager_->save_all_maps();
1052  return true;
1054  context_manager_->save_map_as_dialog();
1055  return true;
1058 
1059  if(!current_addon_id_.empty()) {
1060  context_manager_->save_scenario_as_dialog();
1061  }
1062  return true;
1064  context_manager_->generate_map_dialog();
1065  return true;
1067  context_manager_->apply_mask_dialog();
1068  return true;
1070  context_manager_->create_mask_to_dialog();
1071  return true;
1073  context_manager_->resize_map_dialog();
1074  return true;
1075 
1076  // Side specific ones
1078  if(get_current_map_context().teams().size() >= 9) {
1079  size_t new_side_num = get_current_map_context().teams().size() + 1;
1080  toolkit_->get_palette_manager()->location_palette_->add_item(std::to_string(new_side_num));
1081  }
1083  gui_->init_flags();
1084  return true;
1086  gui_->set_team(0, true);
1087  gui_->set_playing_team(0);
1089  return true;
1091  context_manager_->edit_side_dialog(gui_->viewing_team());
1092  return true;
1093 
1094  // Transitions
1096  context_manager_->set_update_transitions_mode(2);
1097  return true;
1099  context_manager_->set_update_transitions_mode(1);
1100  return true;
1102  context_manager_->set_update_transitions_mode(0);
1103  return true;
1105  if(context_manager_->toggle_update_transitions()) {
1106  return true;
1107  }
1108  [[fallthrough]];
1110  context_manager_->refresh_all();
1111  return true;
1112  // Refresh
1113  case HOTKEY_EDITOR_REFRESH:
1114  context_manager_->reload_map();
1115  return true;
1118  return true;
1119 
1123  gui().invalidate_all();
1124  return true;
1128  gui().invalidate_all();
1129  return true;
1133  gui().invalidate_all();
1134  return true;
1136  location_palette* lp = dynamic_cast<location_palette*>(&toolkit_->get_palette_manager()->active_palette());
1137  if (lp) {
1138  perform_delete(std::make_unique<editor_action_starting_position>(map_location(), lp->selected_item()));
1139  // No idea if this is the right thing to call, but it ensures starting
1140  // position labels get removed on delete.
1141  context_manager_->refresh_after_action();
1142  }
1143  return true;
1144  }
1145  default:
1146  return hotkey::command_executor::do_execute_command(cmd, press, release);
1147  }
1148 }
1149 
1151  if(current_addon_id_.empty()) {
1153  }
1154  context_manager_->set_addon_id(current_addon_id_);
1155 }
1156 
1158 {
1159  help::show_help("..editor");
1160 }
1161 
1162 void editor_controller::show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& disp)
1163 {
1164  if(context_menu) {
1165  if(!get_current_map_context().map().on_board_with_border(gui().hex_clicked_on(xloc, yloc))) {
1166  return;
1167  }
1168  }
1169 
1170  std::vector<config> items;
1171  for(const auto& c : items_arg) {
1172  const std::string& id = c["id"];
1173 
1175 
1176  if((can_execute_command(cmd) && (!context_menu || in_context_menu(cmd)))
1178  {
1179  items.emplace_back("id", id);
1180  }
1181  }
1182 
1183  // No point in showing an empty menu.
1184  if(items.empty()) {
1185  return;
1186  }
1187 
1188  // Based on the ID of the first entry, we fill the menu contextually.
1189  const std::string& first_id = items.front()["id"];
1190 
1191  if(first_id == "EDITOR-LOAD-MRU-PLACEHOLDER") {
1193  context_manager_->expand_load_mru_menu(items, 0);
1194  }
1195 
1196  if(first_id == "editor-switch-map") {
1198  context_manager_->expand_open_maps_menu(items, 0);
1199  }
1200 
1201  if(first_id == "editor-palette-groups") {
1203  toolkit_->get_palette_manager()->active_palette().expand_palette_groups_menu(items, 0);
1204  }
1205 
1206  if(first_id == "editor-switch-side") {
1208  context_manager_->expand_sides_menu(items, 0);
1209  }
1210 
1211  if(first_id == "editor-switch-area") {
1213  context_manager_->expand_areas_menu(items, 0);
1214  }
1215 
1216  if(first_id == "editor-pbl") {
1218  }
1219 
1220  if(!items.empty() && items.front()["id"] == "editor-switch-time") {
1222  context_manager_->expand_time_menu(items, 0);
1223  }
1224 
1225  if(first_id == "editor-assign-local-time") {
1227  context_manager_->expand_local_time_menu(items, 0);
1228  }
1229 
1230  if(first_id == "menu-unit-facings") {
1232  auto pos = items.erase(items.begin());
1233  int dir = 0;
1234  std::generate_n(std::inserter<std::vector<config>>(items, pos), static_cast<int>(map_location::NDIRECTIONS), [&dir]() -> config {
1236  });
1237  }
1238 
1239  if(first_id == "editor-playlist") {
1241  auto pos = items.erase(items.begin());
1242  std::transform(music_tracks_.begin(), music_tracks_.end(), std::inserter<std::vector<config>>(items, pos), [](const sound::music_track& track) -> config {
1243  return config {"label", track.title().empty() ? track.id() : track.title()};
1244  });
1245  }
1246 
1247  if(first_id == "editor-assign-schedule") {
1249  auto pos = items.erase(items.begin());
1250  std::transform(tods_.begin(), tods_.end(), std::inserter<std::vector<config>>(items, pos), [](const tods_map::value_type& tod) -> config {
1251  return config {"label", tod.second.first};
1252  });
1253  }
1254 
1255  if(first_id == "editor-assign-local-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  command_executor::show_menu(items, xloc, yloc, context_menu, disp);
1264 }
1265 
1267 {
1268  gui_->clear_help_string();
1269  gui2::dialogs::preferences_dialog::display();
1270 
1271  gui_->queue_rerender();
1272 }
1273 
1275 {
1276  prefs::get().set_grid(!prefs::get().grid());
1277  gui_->invalidate_all();
1278 }
1279 
1281 {
1282  map_location loc = gui_->mouseover_hex();
1283  const unit_map & units = get_current_map_context().units();
1284  const unit_map::const_unit_iterator un = units.find(loc);
1285  if(un != units.end()) {
1286  help::show_unit_help(un->type_id(), un->type().show_variations_in_help(), false);
1287  } else {
1288  help::show_help("..units");
1289  }
1290 }
1291 
1292 
1294 {
1295  if (!get_current_map_context().map().selection().empty()) {
1296  context_manager_->get_clipboard() = map_fragment(get_current_map_context().map(), get_current_map_context().map().selection());
1297  context_manager_->get_clipboard().center_by_mass();
1298  }
1299 }
1300 
1302 {
1303  map_location loc = gui_->mouseover_hex();
1304  unit_map& units = get_current_map_context().units();
1305  const unit_map::unit_iterator& un = units.find(loc);
1306 
1307  const std::string title(N_("Change Unit ID"));
1308  const std::string label(N_("ID:"));
1309 
1310  if(un != units.end()) {
1311  std::string id = un->id();
1312  if (gui2::dialogs::edit_text::execute(title, label, id)) {
1313  un->set_id(id);
1314  }
1315  }
1316 }
1317 
1319 {
1320  map_location loc = gui_->mouseover_hex();
1321  unit_map& units = get_current_map_context().units();
1322  const unit_map::unit_iterator& un = units.find(loc);
1323 
1324  const std::string title(N_("Rename Unit"));
1325  const std::string label(N_("Name:"));
1326 
1327  if(un != units.end()) {
1328  std::string name = un->name();
1329  if(gui2::dialogs::edit_text::execute(title, label, name)) {
1330  //TODO we may not want a translated name here.
1331  un->set_name(name);
1332  }
1333  }
1334 }
1335 
1337 {
1339 }
1340 
1342 {
1343  copy_selection();
1345 }
1346 
1348 {
1349  const std::set<map_location>& area = get_current_map_context().map().selection();
1351 }
1352 
1354 {
1355  const std::set<map_location>& area = get_current_map_context().map().selection();
1357 }
1358 
1360 {
1361  std::stringstream ssx, ssy;
1362  std::set<map_location>::const_iterator i = get_current_map_context().map().selection().begin();
1363  if (i != get_current_map_context().map().selection().end()) {
1364  ssx << "x = " << i->wml_x();
1365  ssy << "y = " << i->wml_y();
1366  ++i;
1367  while (i != get_current_map_context().map().selection().end()) {
1368  ssx << ", " << i->wml_x();
1369  ssy << ", " << i->wml_y();
1370  ++i;
1371  }
1372  ssx << "\n" << ssy.str() << "\n";
1373  desktop::clipboard::copy_to_clipboard(ssx.str(), false);
1374  }
1375 }
1376 
1377 void editor_controller::perform_delete(std::unique_ptr<editor_action> action)
1378 {
1379  if (action) {
1381  }
1382 }
1383 
1384 void editor_controller::perform_refresh_delete(std::unique_ptr<editor_action> action, bool drag_part /* =false */)
1385 {
1386  if (action) {
1387  context_manager_->perform_refresh(*action, drag_part);
1388  }
1389 }
1390 
1392 {
1394  context_manager_->refresh_all();
1395 }
1396 
1398 {
1399  set_button_state();
1400  toolkit_->adjust_size();
1402 }
1403 
1405 {
1407  context_manager_->refresh_after_action();
1408 }
1409 
1411 {
1413  context_manager_->refresh_after_action();
1414 }
1415 
1416 void editor_controller::mouse_motion(int x, int y, const bool /*browse*/,
1417  bool update, map_location /*new_loc*/)
1418 {
1419  if (mouse_handler_base::mouse_motion_default(x, y, update)) return;
1420  map_location hex_clicked = gui().hex_clicked_on(x, y);
1421  if (get_current_map_context().map().on_board_with_border(drag_from_hex_) && is_dragging()) {
1422  std::unique_ptr<editor_action> a;
1423  bool partial = false;
1424  // last_undo is a non-owning pointer. Although it could have other uses, it seems to be
1425  // mainly (only?) used for printing debugging information.
1426  auto last_undo = get_current_map_context().last_undo_action();
1427  if (dragging_left_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(1)) != 0) {
1428  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
1429  a = get_mouse_action().drag_left(*gui_, x, y, partial, last_undo);
1430  } else if (dragging_right_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(3)) != 0) {
1431  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
1432  a = get_mouse_action().drag_right(*gui_, x, y, partial, last_undo);
1433  }
1434  //Partial means that the mouse action has modified the
1435  //last undo action and the controller shouldn't add
1436  //anything to the undo stack (hence a different perform_ call)
1437  if (a != nullptr) {
1438  if (partial) {
1440  } else {
1442  }
1443  context_manager_->refresh_after_action(true);
1444  }
1445  } else {
1446  get_mouse_action().move(*gui_, hex_clicked);
1447  }
1448  gui().highlight_hex(hex_clicked);
1449 }
1450 
1451 void editor_controller::touch_motion(int /* x */, int /* y */, const bool /* browse */, bool /* update */, map_location /* new_loc */)
1452 {
1453  // Not implemented at all. Sorry, it's a very low priority for iOS port.
1454 }
1455 
1457 {
1458  return get_current_map_context().map().on_board_with_border(gui().hex_clicked_on(x,y));
1459 }
1460 
1461 bool editor_controller::right_click_show_menu(int /*x*/, int /*y*/, const bool /*browse*/)
1462 {
1464 }
1465 
1466 bool editor_controller::left_click(int x, int y, const bool browse)
1467 {
1468  toolkit_->clear_mouseover_overlay();
1469  if (mouse_handler_base::left_click(x, y, browse))
1470  return true;
1471 
1472  LOG_ED << "Left click, after generic handling";
1473  map_location hex_clicked = gui().hex_clicked_on(x, y);
1474  if (!get_current_map_context().map().on_board_with_border(hex_clicked))
1475  return true;
1476 
1477  LOG_ED << "Left click action " << hex_clicked;
1478  auto a = get_mouse_action().click_left(*gui_, x, y);
1479  if(a) {
1480  perform_refresh_delete(std::move(a), true);
1481  set_button_state();
1482  }
1483 
1484  return false;
1485 }
1486 
1487 void editor_controller::left_drag_end(int x, int y, const bool /*browse*/)
1488 {
1489  auto a = get_mouse_action().drag_end_left(*gui_, x, y);
1490  perform_delete(std::move(a));
1491 }
1492 
1493 void editor_controller::left_mouse_up(int x, int y, const bool /*browse*/)
1494 {
1495  auto a = get_mouse_action().up_left(*gui_, x, y);
1496  if(a) {
1497  perform_delete(std::move(a));
1498  set_button_state();
1499  }
1500  toolkit_->set_mouseover_overlay();
1501  context_manager_->refresh_after_action();
1502 }
1503 
1504 bool editor_controller::right_click(int x, int y, const bool browse)
1505 {
1506  toolkit_->clear_mouseover_overlay();
1507  if (mouse_handler_base::right_click(x, y, browse)) return true;
1508  LOG_ED << "Right click, after generic handling";
1509  map_location hex_clicked = gui().hex_clicked_on(x, y);
1510  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return true;
1511  LOG_ED << "Right click action " << hex_clicked;
1512  auto a = get_mouse_action().click_right(*gui_, x, y);
1513  if(a) {
1514  perform_refresh_delete(std::move(a), true);
1515  set_button_state();
1516  }
1517  return false;
1518 }
1519 
1520 void editor_controller::right_drag_end(int x, int y, const bool /*browse*/)
1521 {
1522  auto a = get_mouse_action().drag_end_right(*gui_, x, y);
1523  perform_delete(std::move(a));
1524 }
1525 
1526 void editor_controller::right_mouse_up(int x, int y, const bool browse)
1527 {
1528  // Call base method to handle context menus.
1529  mouse_handler_base::right_mouse_up(x, y, browse);
1530 
1531  auto a = get_mouse_action().up_right(*gui_, x, y);
1532  if(a) {
1533  perform_delete(std::move(a));
1534  set_button_state();
1535  }
1536  toolkit_->set_mouseover_overlay();
1537  context_manager_->refresh_after_action();
1538 }
1539 
1541 {
1542  const map_location& loc = gui().mouseover_hex();
1543  if (get_current_map_context().map().on_board(loc) == false)
1544  return;
1545 
1548 }
1549 
1550 void editor_controller::process_keyup_event(const SDL_Event& event)
1551 {
1552  auto a = get_mouse_action().key_event(gui(), event);
1553  perform_refresh_delete(std::move(a));
1554  toolkit_->set_mouseover_overlay();
1555 }
1556 
1558  return this;
1559 }
1560 
1562 {
1564 }
1565 
1567 {
1569 }
1570 
1572 {
1574 }
1575 
1577 {
1579 }
1580 
1582 {
1583  return toolkit_->get_palette_manager()->active_palette().action_pressed();
1584 }
1585 
1586 } //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:159
child_itors child_range(config_key_type key)
Definition: config.cpp:273
void set_scroll_up(bool on)
void set_scroll_left(bool on)
virtual bool in_context_menu(const hotkey::ui_command &cmd) const
virtual void play_slice(bool is_delay_enabled=true)
void set_scroll_right(bool on)
const game_config_view & game_config_
void set_scroll_down(bool on)
Sort-of-Singleton that many classes, both GUI and non-GUI, use to access the game data.
Definition: display.hpp:88
void toggle_debug_flag(DEBUG_FLAG flag)
Definition: display.hpp:1006
const 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:557
virtual void highlight_hex(map_location hex)
Definition: display.cpp:1512
@ DEBUG_COORDINATES
Overlays x,y coords on tiles.
Definition: display.hpp:978
@ DEBUG_NUM_BITMAPS
Overlays number of bitmaps on tiles.
Definition: display.hpp:984
@ DEBUG_TERRAIN_CODES
Overlays terrain codes on tiles.
Definition: display.hpp:981
void invalidate_all()
Function to invalidate all tiles.
Definition: display.cpp:3138
surface screenshot(bool map_screenshot=false)
Capture a (map-)screenshot into a surface.
Definition: display.cpp:757
void queue_rerender()
Marks everything for rendering including all tiles and sidebar.
Definition: display.cpp:2324
void set_debug_flag(DEBUG_FLAG flag, bool value)
Definition: display.hpp:1001
const map_location & mouseover_hex() const
Definition: display.hpp:308
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
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 initialize_addon_if_empty()
Initialize an addon if the addon id is empty.
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.
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:389
const terrain_type & get_terrain_info(const t_translation::terrain_code &terrain) const
Definition: map.cpp:97
const std::vector< time_of_day > get_schedule()
Return current schedule.
Definition: custom_tod.cpp:364
void register_callback(std::function< void(std::vector< time_of_day >)>)
Register callback for update.
Definition: custom_tod.cpp:370
Dialog that allows user to create custom unit types.
Definition: edit_unit.hpp:36
void write()
Write the cfg file.
Definition: edit_unit.cpp:1072
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
void set_editor_draw_hex_coordinates(bool value)
void set_editor_draw_num_of_bitmaps(bool value)
static prefs & get()
void set_editor_draw_terrain_codes(bool value)
bool grid()
void set_grid(bool ison)
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:968
#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:207
Contains functions for cleanly handling SDL input.
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, const bool)
Copies text to the clipboard.
Definition: clipboard.cpp:32
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:31
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:193
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:203
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:150
void show_help(const std::string &show_topic, int xloc, int yloc)
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, int xloc, int yloc)
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_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:216
save_result save_image(const locator &i_locator, const std::string &filename)
Definition: picture.cpp:924
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:177
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:601
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:38
DIRECTION
Valid directions which can be moved in our hexagonal world.
Definition: location.hpp:40
bool valid() const
Definition: location.hpp:89
static std::string write_translated_direction(DIRECTION dir)
Definition: location.cpp:161
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 a
#define b