The Battle for Wesnoth  1.19.3+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  gui().set_help_string_enabled(prefs::get().editor_help_text_shown());
111 // halo_manager_.reset(new halo::manager(*gui_));
112 // resources::halo = halo_manager_.get();
113 // ^ These lines no longer necessary, the gui owns its halo manager.
114 // TODO: Should the editor map contexts actually own the halo manager and swap them in and out from the gui?
115 // 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
116 // without deleting it.
117 }
118 
120 {
121  for (const config &schedule : game_config.child_range("editor_times")) {
122 
123  const std::string& schedule_id = schedule["id"];
124  /* Use schedule id as the name if schedule name is empty */
125  const std::string& schedule_name = schedule["name"].empty() ? schedule["id"] : schedule["name"];
126  if (schedule_id.empty()) {
127  ERR_ED << "Missing ID attribute in a TOD Schedule.";
128  continue;
129  }
130 
131  tods_map::iterator times = tods_.find(schedule_id);
132  if (times == tods_.end()) {
133  std::pair<tods_map::iterator, bool> new_times =
134  tods_.emplace(schedule_id, std::pair(schedule_name, std::vector<time_of_day>()));
135  times = new_times.first;
136  } else {
137  ERR_ED << "Duplicate TOD Schedule identifiers.";
138  continue;
139  }
140 
141  for (const config &time : schedule.child_range("time")) {
142  times->second.second.emplace_back(time);
143  }
144 
145  }
146 
147  if (tods_.empty()) {
148  ERR_ED << "No editor time-of-day defined";
149  }
150 }
151 
153 {
154  const std::string tag_name = "editor_music";
155  if (game_config.child_range(tag_name).size() == 0) {
156  ERR_ED << "No editor music defined";
157  }
158  else {
159  for (const config& editor_music : game_config.child_range(tag_name)) {
160  for (const config& music : editor_music.child_range("music")) {
161  sound::music_track track(music);
162  if (track.file_path().empty())
163  WRN_ED << "Music track " << track.id() << " not found.";
164  else
165  music_tracks_.emplace_back(music);
166  }
167  }
168  }
169 }
170 
172 {
173  resources::tod_manager = nullptr;
174  resources::filter_con = nullptr;
175 
176  resources::classification = nullptr;
177 }
178 
180 {
181  try {
182  while (!do_quit_) {
183  play_slice();
184  }
185  } catch (const editor_exception& e) {
186  gui2::show_transient_message(_("Fatal error"), e.what());
187  return EXIT_ERROR;
188  } catch (const wml_exception& e) {
189  e.show();
190  }
191  return quit_mode_;
192 }
193 
195 }
196 
197 void editor_controller::do_screenshot(const std::string& screenshot_filename /* = "map_screenshot.png" */)
198 {
199  try {
200  surface screenshot = gui().screenshot(true);
201  if(!screenshot || image::save_image(screenshot, screenshot_filename) != image::save_result::success) {
202  ERR_ED << "Screenshot creation failed!";
203  }
204  } catch (const wml_exception& e) {
205  e.show();
206  }
207 }
208 
210 {
211  std::string modified;
212  std::size_t amount = context_manager_->modified_maps(modified);
213 
214  std::string message;
215  if (amount == 0) {
216  message = _("Do you really want to quit?");
217  } else if (amount == 1 && get_current_map_context().modified()) {
218  message = _("Do you really want to quit? Changes to this map since the last save will be lost.");
219  } else {
220  message = _("Do you really want to quit? The following maps were modified and all changes since the last save will be lost:");
221  message += "\n" + modified;
222  }
223  return quit_confirmation::show_prompt(message);
224 }
225 
227 {
229  if (unit_dlg.show()) {
230  unit_dlg.write();
231  }
232 }
233 
235 {
236  if (tods_.empty()) {
237  gui2::show_error_message(_("No editor time-of-day found."));
238  return;
239  }
240 
242  std::vector<time_of_day> prev_schedule = manager.times();
243 
244  gui2::dialogs::custom_tod tod_dlg(manager.times(), manager.get_current_time(), current_addon_id_);
245 
246  /* Register callback to the dialog so that the map changes can be
247  * previewed in real time.
248  */
249  std::function<void(std::vector<time_of_day>)> update_func(
250  std::bind(
252  this,
253  std::placeholders::_1));
254  tod_dlg.register_callback(update_func);
255 
256  /* Autogenerate schedule id */
257  std::int64_t current_millis = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
258  std::string sch_id = current_addon_id_+"-schedule";
259  /* Set correct textdomain */
260  t_string sch_name("", "wesnoth-"+current_addon_id_);
261 
262  // TODO : Needs better error handling messages
263  /* Show dialog and update current schedule */
264  if(tod_dlg.show()) {
265  /* Save the new schedule */
266  std::vector<time_of_day> schedule = tod_dlg.get_schedule();
267  if(!gui2::dialogs::tod_new_schedule::execute(sch_id, sch_name)) {
268  /* User pressed Cancel. Restore old schedule */
269  update_map_schedule(prev_schedule);
270  return;
271  }
272 
273  /* In case the ID or Name field is blank and user presses OK */
274  if (sch_id.empty()) {
275  sch_id = current_addon_id_+"-schedule-"+std::to_string(current_millis);
276  } else {
277  /* Check if the id entered is same as any of the existing ids
278  * If so, replace */
279  // TODO : Notify the user if they enter an already existing schedule ID
280  for (auto map_elem : tods_) {
281  if (sch_id == map_elem.first) {
282  sch_id = current_addon_id_+"-schedule-"+std::to_string(current_millis);
283  }
284  }
285  }
286 
287  tods_.emplace(sch_id, std::pair(sch_name, schedule));
289  get_current_map_context().save_schedule(sch_id, sch_name);
290  gui_->update_tod();
291  context_manager_->refresh_all();
292  } else {
293  /* Restore old schedule */
294  update_map_schedule(prev_schedule);
295  }
296 }
297 
298 void editor_controller::update_map_schedule(std::vector<time_of_day> schedule)
299 {
301  gui_->update_tod();
302  context_manager_->refresh_all();
303 }
304 
306 {
307  using namespace hotkey; //reduce hotkey:: clutter
308  int index = cmd.index;
309  switch(cmd.hotkey_command) {
310  case HOTKEY_NULL:
311  if (index >= 0) {
312  unsigned i = static_cast<unsigned>(index);
313 
314  switch (active_menu_) {
315  case editor::MAP:
316  if (i < context_manager_->open_maps()) {
317  return true;
318  }
319  return false;
320  case editor::LOAD_MRU:
321  case editor::PALETTE:
322  case editor::AREA:
323  case editor::ADDON:
324  case editor::SIDE:
325  case editor::TIME:
326  case editor::SCHEDULE:
328  case editor::MUSIC:
329  case editor::LOCAL_TIME:
330  case editor::UNIT_FACING:
331  return true;
332  }
333  }
334  return false;
336  return true;
338  return toolkit_->get_palette_manager()->can_scroll_up();
340  return toolkit_->get_palette_manager()->can_scroll_down();
341  case HOTKEY_ZOOM_IN:
342  return !gui_->zoom_at_max();
343  case HOTKEY_ZOOM_OUT:
344  return !gui_->zoom_at_min();
345  case HOTKEY_ZOOM_DEFAULT:
346  case HOTKEY_FULLSCREEN:
347  case HOTKEY_SCREENSHOT:
349  case HOTKEY_TOGGLE_GRID:
350  case HOTKEY_MOUSE_SCROLL:
351  case HOTKEY_ANIMATE_MAP:
352  case HOTKEY_MUTE:
353  case HOTKEY_PREFERENCES:
354  case HOTKEY_HELP:
355  case HOTKEY_QUIT_GAME:
356  case HOTKEY_SCROLL_UP:
357  case HOTKEY_SCROLL_DOWN:
358  case HOTKEY_SCROLL_LEFT:
359  case HOTKEY_SCROLL_RIGHT:
360  return true; //general hotkeys we can always do
361 
362  case HOTKEY_UNIT_LIST:
363  return !get_current_map_context().units().empty();
364 
365  // TODO Disabling this for now until the functionality can be implemnted.
366  // See the status_table() method
367  case HOTKEY_STATUS_TABLE:
368  //return !get_current_map_context().teams().empty();
369  return false;
370  /////////////////////////////
371 
373  return gui().mouseover_hex().valid();
374 
375  // unit tool related
376  case HOTKEY_DELETE_UNIT:
377  case HOTKEY_RENAME_UNIT:
384  {
385  map_location loc = gui_->mouseover_hex();
386  const unit_map& units = get_current_map_context().units();
387  return (toolkit_->is_mouse_action_set(HOTKEY_EDITOR_TOOL_UNIT) &&
388  units.find(loc) != units.end());
389  }
390 
391  case HOTKEY_UNDO:
394  case HOTKEY_REDO:
396 
403  return true;
404 
405  // Can be enabled as long as a valid addon_id is set
407  return !current_addon_id_.empty();
408 
409  // Only enable when editing a scenario
413 
414  case HOTKEY_EDITOR_PBL:
418  return true;
419 
423 
426  return !get_current_map_context().teams().empty();
427 
428  // brushes
436 
438  return true;
440  return toolkit_->get_palette_manager()->active_palette().supports_swap();
444  {
445  std::string dummy;
446  return context_manager_->modified_maps(dummy) > 1;
447  }
453  return true;
455  return !get_current_map_context().get_filename().empty()
457 
458  // Tools
459  // Pure map editing tools this can be used all the time.
464  return true;
465  // WWL dependent tools which don't rely on defined sides.
472  return !get_current_map_context().teams().empty();
473 
477  return !get_current_map_context().is_pure_map() &&
479 
481  return !get_current_map_context().is_pure_map() &&
483  && !get_current_map_context().map().selection().empty();
484 
489  return !get_current_map_context().map().selection().empty()
490  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
492  return (get_current_map_context().map().selection().size() > 1
493  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE));
497  return !context_manager_->clipboard_empty();
502  return !context_manager_->clipboard_empty()
503  && toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
506  return !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
508  return !get_current_map_context().map().selection().empty()
510  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
528  return true;
532  return true;
533  default:
534  return false;
535  }
536 }
537 
539 {
540  using namespace hotkey;
541  int index = cmd.index;
542  switch (cmd.hotkey_command) {
543 
545  {
547  get_current_map_context().units().find(gui_->mouseover_hex());
548  return un->loyal() ? ACTION_ON : ACTION_OFF;
549 
550  }
552  {
554  get_current_map_context().units().find(gui_->mouseover_hex());
555  return un->can_recruit() ? ACTION_ON : ACTION_OFF;
556  }
558  {
560  get_current_map_context().units().find(gui_->mouseover_hex());
561  return (!un->unrenamable()) ? ACTION_ON : ACTION_OFF;
562  }
563  //TODO remove hardcoded hotkey names
565  return context_manager_->is_active_transitions_hotkey("editor-auto-update-transitions")
568  return context_manager_->is_active_transitions_hotkey("editor-partial-update-transitions")
571  return context_manager_->is_active_transitions_hotkey("editor-no-update-transitions")
574  return toolkit_->is_active_brush("brush-1") ? ACTION_ON : ACTION_OFF;
576  return toolkit_->is_active_brush("brush-2") ? ACTION_ON : ACTION_OFF;
578  return toolkit_->is_active_brush("brush-3") ? ACTION_ON : ACTION_OFF;
580  return toolkit_->is_active_brush("brush-nw-se") ? ACTION_ON : ACTION_OFF;
582  return toolkit_->is_active_brush("brush-sw-ne") ? ACTION_ON : ACTION_OFF;
583 
584  case HOTKEY_TOGGLE_GRID:
585  return prefs::get().grid() ? ACTION_ON : ACTION_OFF;
590  return get_current_map_context().map().selection().empty() ?
601  return toolkit_->is_mouse_action_set(cmd.hotkey_command) ? ACTION_ON : ACTION_OFF;
603  return gui_->debug_flag_set(display::DEBUG_COORDINATES) ? ACTION_ON : ACTION_OFF;
605  return gui_->debug_flag_set(display::DEBUG_TERRAIN_CODES) ? ACTION_ON : ACTION_OFF;
607  return gui_->debug_flag_set(display::DEBUG_NUM_BITMAPS) ? ACTION_ON : ACTION_OFF;
609  return gui_->help_string_enabled() ? ACTION_ON : ACTION_OFF;
611  return (prefs::get().minimap_draw_villages()) ? ACTION_ON : ACTION_OFF;
613  return (prefs::get().minimap_movement_coding()) ? ACTION_ON : ACTION_OFF;
615  return (prefs::get().minimap_terrain_coding()) ? ACTION_ON : ACTION_OFF;
617  return (prefs::get().minimap_draw_units()) ? ACTION_ON : ACTION_OFF;
619  return (prefs::get().minimap_draw_terrain()) ? ACTION_ON : ACTION_OFF;
620  case HOTKEY_ZOOM_DEFAULT:
621  return (gui_->get_zoom_factor() == 1.0) ? ACTION_ON : ACTION_OFF;
622 
623  case HOTKEY_NULL:
624  switch (active_menu_) {
625  case editor::MAP:
626  return index == context_manager_->current_context_index()
628  case editor::LOAD_MRU:
629  return ACTION_STATELESS;
630  case editor::PALETTE:
631  return ACTION_STATELESS;
632  case editor::AREA:
635  case editor::ADDON:
636  return ACTION_STATELESS;
637  case editor::SIDE:
638  return static_cast<std::size_t>(index) == gui_->playing_team_index()
640  case editor::TIME:
643  case editor::LOCAL_TIME:
645  get_current_map_context().get_active_area())
647  case editor::MUSIC:
649  ? ACTION_ON : ACTION_OFF;
650  case editor::SCHEDULE:
651  {
652  tods_map::const_iterator it = tods_.begin();
653  std::advance(it, index);
654  const std::vector<time_of_day>& times1 = it->second.second;
655  const std::vector<time_of_day>& times2 = get_current_map_context().get_time_manager()->times();
656  return (times1 == times2) ? ACTION_SELECTED : ACTION_DESELECTED;
657  }
659  {
660  tods_map::const_iterator it = tods_.begin();
661  std::advance(it, index);
662  const std::vector<time_of_day>& times1 = it->second.second;
663  int active_area = get_current_map_context().get_active_area();
664  const std::vector<time_of_day>& times2 = get_current_map_context().get_time_manager()->times(active_area);
665  return (times1 == times2) ? ACTION_SELECTED : ACTION_DESELECTED;
666  }
667  case editor::UNIT_FACING:
668  {
670  assert(un != get_current_map_context().units().end());
671  return un->facing() == index ? ACTION_SELECTED : ACTION_DESELECTED;
672  }
673  }
674  return ACTION_ON;
675  default:
676  return command_executor::get_action_state(cmd);
677  }
678 }
679 
680 bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool press, bool release)
681 {
682  using namespace hotkey;
683  HOTKEY_COMMAND command = cmd.hotkey_command;
684  SCOPE_ED;
685  int index = cmd.index;
686 
687  // nothing here handles release; fall through to base implementation
688  if (!press) {
689  return command_executor::do_execute_command(cmd, press, release);
690  }
691 
692  switch (command) {
693  case HOTKEY_NULL:
694  switch (active_menu_) {
695  case MAP:
696  if (index >= 0) {
697  unsigned i = static_cast<unsigned>(index);
698  if (i < context_manager_->size()) {
699  context_manager_->switch_context(index);
700  toolkit_->hotkey_set_mouse_action(HOTKEY_EDITOR_TOOL_PAINT);
701  return true;
702  }
703  }
704  return false;
705  case LOAD_MRU:
706  if (index >= 0) {
707  context_manager_->load_mru_item(static_cast<unsigned>(index));
708  }
709  return true;
710  case PALETTE:
711  toolkit_->get_palette_manager()->set_group(index);
712  return true;
713  case SIDE:
714  gui_->set_viewing_team_index(index, true);
715  gui_->set_playing_team_index(index);
716  toolkit_->get_palette_manager()->draw_contents();
717  return true;
718  case AREA:
719  {
721  const std::set<map_location>& area =
723  std::vector<map_location> locs(area.begin(), area.end());
725  gui_->scroll_to_tiles(locs.begin(), locs.end());
726  return true;
727  }
728  case ADDON:
729  return true;
730  case TIME:
731  {
733  gui_->update_tod();
734  return true;
735  }
736  case LOCAL_TIME:
737  {
739  return true;
740  }
741  case MUSIC:
742  {
743  //TODO mark the map as changed
746  std::vector<config> items;
747  items.emplace_back("id", "editor-playlist");
748  std::shared_ptr<gui::button> b = gui_->find_menu_button("menu-playlist");
749  show_menu(items, b->location().x +1, b->location().y + b->height() +1, false, *gui_);
750  return true;
751  }
752  case SCHEDULE:
753  {
754  tods_map::iterator iter = tods_.begin();
755  std::advance(iter, index);
756  get_current_map_context().replace_schedule(iter->second.second);
757  // TODO: test again after the assign-schedule menu is fixed. Should work, though.
758  gui_->update_tod();
759  return true;
760  }
761  case LOCAL_SCHEDULE:
762  {
763  tods_map::iterator iter = tods_.begin();
764  std::advance(iter, index);
765  get_current_map_context().replace_local_schedule(iter->second.second);
766  return true;
767  }
768  case UNIT_FACING:
769  {
771  assert(un != get_current_map_context().units().end());
772  un->set_facing(map_location::DIRECTION(index));
773  un->anim_comp().set_standing();
774  return true;
775  }
776  }
777  return true;
778 
779  //Zoom
780  case HOTKEY_ZOOM_IN:
781  gui_->set_zoom(true);
783  toolkit_->set_mouseover_overlay(*gui_);
784  return true;
785  case HOTKEY_ZOOM_OUT:
786  gui_->set_zoom(false);
788  toolkit_->set_mouseover_overlay(*gui_);
789  return true;
790  case HOTKEY_ZOOM_DEFAULT:
791  gui_->toggle_default_zoom();
793  toolkit_->set_mouseover_overlay(*gui_);
794  return true;
795 
796  //Palette
798  //TODO this code waits for the gui2 dialog to get ready
799  // std::vector< std::pair< std::string, std::string >> blah_items;
800  // toolkit_->get_palette_manager()->active_palette().expand_palette_groups_menu(blah_items);
801  // int selected = 1; //toolkit_->get_palette_manager()->active_palette().get_selected;
802  // gui2::teditor_select_palette_group::execute(selected, blah_items);
803  return true;
805  toolkit_->get_palette_manager()->scroll_up();
806  return true;
808  toolkit_->get_palette_manager()->scroll_down();
809  return true;
810 
811  case HOTKEY_QUIT_GAME:
813  do_quit_ = true;
815  }
816  return true;
819  return true;
821  context_manager_->save_contexts();
822  do_quit_ = true;
824  return true;
827  return true;
830  return true;
832  toolkit_->get_palette_manager()->active_palette().swap();
833  return true;
835  if (dynamic_cast<const editor_action_chain*>(get_current_map_context().last_undo_action()) != nullptr) {
837  context_manager_->refresh_after_action();
838  } else {
839  undo();
840  }
841  return true;
842 
843  //Tool Selection
852  toolkit_->hotkey_set_mouse_action(command);
853  return true;
854 
855  case HOTKEY_EDITOR_PBL:
856  if(initialize_addon()) {
857  context_manager_->edit_pbl();
858  }
859  return true;
860 
862  if(initialize_addon()) {
863  context_manager_->change_addon_id();
864  }
865  return true;
866 
869  return true;
870 
872  {
873  if (!initialize_addon()) {
874  gui2::show_error_message("Could not initialize add-on!");
875  return true;
876  }
877 
879 
880  dlg.set_title(_("Add-on Files"))
882 
883  if (dlg.show()) {
884  std::string filepath = dlg.path();
885  if (filesystem::is_map(filepath) || filesystem::is_cfg(filepath)) {
886  // Open map or scenario
887  context_manager_->load_map(filepath, true);
888  } else {
889  // Open file using OS application for that format
891  desktop::open_object(filepath);
892  } else {
893  gui2::show_message("", _("Opening files is not supported, contact your packager"), gui2::dialogs::message::auto_close);
894  }
895  }
896  }
897 
898  return true;
899  }
900 
902  add_area();
903  return true;
904 
906  change_unit_id();
907  return true;
908 
909  return true;
911  {
912  map_location loc = gui_->mouseover_hex();
914  bool unrenamable = un->unrenamable();
915  un->set_unrenamable(!unrenamable);
916  }
917  return true;
919  {
920  map_location loc = gui_->mouseover_hex();
922  bool canrecruit = un->can_recruit();
923  un->set_can_recruit(!canrecruit);
924  un->anim_comp().set_standing();
925  }
926  return true;
928  {
929  map_location loc = gui_->mouseover_hex();
931  bool loyal = un->loyal();
932  un->set_loyal(!loyal);
933  }
934  return true;
935  case HOTKEY_DELETE_UNIT:
936  {
937  map_location loc = gui_->mouseover_hex();
938  perform_delete(std::make_unique<editor_action_unit_delete>(loc));
939  }
940  return true;
941  case HOTKEY_EDITOR_CLIPBOARD_PASTE: //paste is somewhat different as it might be "one action then revert to previous mode"
942  toolkit_->hotkey_set_mouse_action(command);
943  return true;
944 
945  //Clipboard
947  context_manager_->get_clipboard().rotate_60_cw();
948  toolkit_->update_mouse_action_highlights();
949  return true;
951  context_manager_->get_clipboard().rotate_60_ccw();
952  toolkit_->update_mouse_action_highlights();
953  return true;
955  context_manager_->get_clipboard().flip_horizontal();
956  toolkit_->update_mouse_action_highlights();
957  return true;
959  context_manager_->get_clipboard().flip_vertical();
960  toolkit_->update_mouse_action_highlights();
961  return true;
962 
963  //Brushes
965  toolkit_->cycle_brush();
966  return true;
968  toolkit_->set_brush("brush-1");
969  return true;
971  toolkit_->set_brush("brush-2");
972  return true;
974  toolkit_->set_brush("brush-3");
975  return true;
977  toolkit_->set_brush("brush-nw-se");
978  return true;
980  toolkit_->set_brush("brush-sw-ne");
981  return true;
982 
984  copy_selection();
985  return true;
987  cut_selection();
988  return true;
990  context_manager_->rename_area_dialog();
991  return true;
993  save_area();
994  return true;
997  return true;
999  if(!get_current_map_context().map().everything_selected()) {
1000  context_manager_->perform_refresh(editor_action_select_all());
1001  return true;
1002  }
1003  [[fallthrough]];
1005  context_manager_->perform_refresh(editor_action_select_inverse());
1006  return true;
1008  context_manager_->perform_refresh(editor_action_select_none());
1009  return true;
1011  context_manager_->fill_selection();
1012  return true;
1015  get_current_map_context().map().selection()));
1016  return true;
1017 
1019  context_manager_->edit_scenario_dialog();
1020  return true;
1021 
1024  get_current_map_context().get_active_area());
1025  return true;
1026 
1027  // map specific
1029  context_manager_->close_current_context();
1030  // Copy behaviour from when switching windows to always reset the active tool to the Paint Tool
1031  // This avoids the situation of having a scenario-specific tool active in a map context which can cause a crash if used
1032  // Not elegant but at least avoids a potential crash and is consistent with existing behaviour
1033  toolkit_->hotkey_set_mouse_action(HOTKEY_EDITOR_TOOL_PAINT);
1034  return true;
1036  context_manager_->load_map_dialog();
1037  return true;
1039  context_manager_->revert_map();
1040  return true;
1041  case HOTKEY_EDITOR_MAP_NEW:
1042  context_manager_->new_map_dialog();
1043  return true;
1045  if(initialize_addon()) {
1046  context_manager_->new_scenario_dialog();
1047  }
1048  return true;
1050  save_map();
1051  return true;
1053  context_manager_->save_all_maps();
1054  return true;
1056  context_manager_->save_map_as_dialog();
1057  return true;
1059  if(initialize_addon()) {
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_viewing_team_index(0, true);
1087  gui_->set_playing_team_index(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 
1122  prefs::get().set_editor_draw_hex_coordinates(gui().debug_flag_set(display::DEBUG_COORDINATES));
1123  gui().invalidate_all();
1124  return true;
1127  prefs::get().set_editor_draw_terrain_codes(gui().debug_flag_set(display::DEBUG_TERRAIN_CODES));
1128  gui().invalidate_all();
1129  return true;
1132  prefs::get().set_editor_draw_num_of_bitmaps(gui().debug_flag_set(display::DEBUG_NUM_BITMAPS));
1133  gui().invalidate_all();
1134  return true;
1136  gui().set_help_string_enabled(!gui().help_string_enabled());
1137  prefs::get().set_editor_help_text_shown(gui().help_string_enabled());
1138  return true;
1140  location_palette* lp = dynamic_cast<location_palette*>(&toolkit_->get_palette_manager()->active_palette());
1141  if (lp) {
1142  perform_delete(std::make_unique<editor_action_starting_position>(map_location(), lp->selected_item()));
1143  // No idea if this is the right thing to call, but it ensures starting
1144  // position labels get removed on delete.
1145  context_manager_->refresh_after_action();
1146  }
1147  return true;
1148  }
1149  default:
1150  return hotkey::command_executor::do_execute_command(cmd, press, release);
1151  }
1152 }
1153 
1155  if(current_addon_id_.empty()) {
1156  // editor::initialize_addon can return empty id in case of failure
1158  }
1159  context_manager_->set_addon_id(current_addon_id_);
1160  return !current_addon_id_.empty();
1161 }
1162 
1164 {
1165  help::show_help("..editor");
1166 }
1167 
1168 void editor_controller::show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& disp)
1169 {
1170  if(context_menu) {
1171  if(!get_current_map_context().map().on_board_with_border(gui().hex_clicked_on(xloc, yloc))) {
1172  return;
1173  }
1174  }
1175 
1176  std::vector<config> items;
1177  for(const auto& c : items_arg) {
1178  const std::string& id = c["id"];
1179 
1181 
1182  if((can_execute_command(cmd) && (!context_menu || in_context_menu(cmd)))
1184  {
1185  items.emplace_back("id", id);
1186  }
1187  }
1188 
1189  // No point in showing an empty menu.
1190  if(items.empty()) {
1191  return;
1192  }
1193 
1194  // Based on the ID of the first entry, we fill the menu contextually.
1195  const std::string& first_id = items.front()["id"];
1196 
1197  if(first_id == "EDITOR-LOAD-MRU-PLACEHOLDER") {
1199  context_manager_->expand_load_mru_menu(items, 0);
1200  }
1201 
1202  if(first_id == "editor-switch-map") {
1204  context_manager_->expand_open_maps_menu(items, 0);
1205  }
1206 
1207  if(first_id == "editor-palette-groups") {
1209  toolkit_->get_palette_manager()->active_palette().expand_palette_groups_menu(items, 0);
1210  }
1211 
1212  if(first_id == "editor-switch-side") {
1214  context_manager_->expand_sides_menu(items, 0);
1215  }
1216 
1217  if(first_id == "editor-switch-area") {
1219  context_manager_->expand_areas_menu(items, 0);
1220  }
1221 
1222  if(first_id == "editor-pbl") {
1224  }
1225 
1226  if(!items.empty() && items.front()["id"] == "editor-switch-time") {
1228  context_manager_->expand_time_menu(items, 0);
1229  }
1230 
1231  if(first_id == "editor-assign-local-time") {
1233  context_manager_->expand_local_time_menu(items, 0);
1234  }
1235 
1236  if(first_id == "menu-unit-facings") {
1238  auto pos = items.erase(items.begin());
1239  int dir = 0;
1240  std::generate_n(std::inserter<std::vector<config>>(items, pos), static_cast<int>(map_location::NDIRECTIONS), [&dir]() -> config {
1242  });
1243  }
1244 
1245  if(first_id == "editor-playlist") {
1247  auto pos = items.erase(items.begin());
1248  std::transform(music_tracks_.begin(), music_tracks_.end(), std::inserter<std::vector<config>>(items, pos), [](const sound::music_track& track) -> config {
1249  return config {"label", track.title().empty() ? track.id() : track.title()};
1250  });
1251  }
1252 
1253  if(first_id == "editor-assign-schedule") {
1255  auto pos = items.erase(items.begin());
1256  std::transform(tods_.begin(), tods_.end(), std::inserter<std::vector<config>>(items, pos), [](const tods_map::value_type& tod) -> config {
1257  return config {"label", tod.second.first};
1258  });
1259  }
1260 
1261  if(first_id == "editor-assign-local-schedule") {
1263  auto pos = items.erase(items.begin());
1264  std::transform(tods_.begin(), tods_.end(), std::inserter<std::vector<config>>(items, pos), [](const tods_map::value_type& tod) -> config {
1265  return config {"label", tod.second.first};
1266  });
1267  }
1268 
1269  command_executor::show_menu(items, xloc, yloc, context_menu, disp);
1270 }
1271 
1273 {
1274  gui_->clear_help_string();
1275  gui2::dialogs::preferences_dialog::display();
1276 
1277  gui_->queue_rerender();
1278 }
1279 
1281 {
1282  prefs::get().set_grid(!prefs::get().grid());
1283  gui_->invalidate_all();
1284 }
1285 
1287 {
1288  map_location loc = gui_->mouseover_hex();
1289  const unit_map & units = get_current_map_context().units();
1290  const unit_map::const_unit_iterator un = units.find(loc);
1291  if(un != units.end()) {
1292  help::show_unit_help(un->type_id(), un->type().show_variations_in_help(), false);
1293  } else {
1294  help::show_help("..units");
1295  }
1296 }
1297 
1298 
1300 {
1301  if (!get_current_map_context().map().selection().empty()) {
1302  context_manager_->get_clipboard() = map_fragment(get_current_map_context().map(), get_current_map_context().map().selection());
1303  context_manager_->get_clipboard().center_by_mass();
1304  }
1305 }
1306 
1308 {
1309  map_location loc = gui_->mouseover_hex();
1310  unit_map& units = get_current_map_context().units();
1311  const unit_map::unit_iterator& un = units.find(loc);
1312 
1313  const std::string title(N_("Change Unit ID"));
1314  const std::string label(N_("ID:"));
1315 
1316  if(un != units.end()) {
1317  std::string id = un->id();
1318  if (gui2::dialogs::edit_text::execute(title, label, id)) {
1319  un->set_id(id);
1320  }
1321  }
1322 }
1323 
1325 {
1326  map_location loc = gui_->mouseover_hex();
1327  unit_map& units = get_current_map_context().units();
1328  const unit_map::unit_iterator& un = units.find(loc);
1329 
1330  const std::string title(N_("Rename Unit"));
1331  const std::string label(N_("Name:"));
1332 
1333  if(un != units.end()) {
1334  std::string name = un->name();
1335  if(gui2::dialogs::edit_text::execute(title, label, name)) {
1336  //TODO we may not want a translated name here.
1337  un->set_name(name);
1338  }
1339  }
1340 }
1341 
1343 {
1345 }
1346 
1348 {
1349  copy_selection();
1351 }
1352 
1354 {
1355  const std::set<map_location>& area = get_current_map_context().map().selection();
1357 }
1358 
1360 {
1361  const std::set<map_location>& area = get_current_map_context().map().selection();
1363 }
1364 
1366 {
1367  std::stringstream ssx, ssy;
1368  std::set<map_location>::const_iterator i = get_current_map_context().map().selection().begin();
1369  if (i != get_current_map_context().map().selection().end()) {
1370  ssx << "x = " << i->wml_x();
1371  ssy << "y = " << i->wml_y();
1372  ++i;
1373  while (i != get_current_map_context().map().selection().end()) {
1374  ssx << ", " << i->wml_x();
1375  ssy << ", " << i->wml_y();
1376  ++i;
1377  }
1378  ssx << "\n" << ssy.str() << "\n";
1379  desktop::clipboard::copy_to_clipboard(ssx.str(), false);
1380  }
1381 }
1382 
1383 void editor_controller::perform_delete(std::unique_ptr<editor_action> action)
1384 {
1385  if (action) {
1387  }
1388 }
1389 
1390 void editor_controller::perform_refresh_delete(std::unique_ptr<editor_action> action, bool drag_part /* =false */)
1391 {
1392  if (action) {
1393  context_manager_->perform_refresh(*action, drag_part);
1394  }
1395 }
1396 
1398 {
1400  context_manager_->refresh_all();
1401 }
1402 
1404 {
1405  set_button_state();
1406  toolkit_->adjust_size();
1408 }
1409 
1411 {
1413  context_manager_->refresh_after_action();
1414 }
1415 
1417 {
1419  context_manager_->refresh_after_action();
1420 }
1421 
1422 void editor_controller::mouse_motion(int x, int y, const bool /*browse*/,
1423  bool update, map_location /*new_loc*/)
1424 {
1425  if (mouse_handler_base::mouse_motion_default(x, y, update)) return;
1426  map_location hex_clicked = gui().hex_clicked_on(x, y);
1427  if (get_current_map_context().map().on_board_with_border(drag_from_hex_) && is_dragging()) {
1428  std::unique_ptr<editor_action> a;
1429  bool partial = false;
1430  // last_undo is a non-owning pointer. Although it could have other uses, it seems to be
1431  // mainly (only?) used for printing debugging information.
1432  auto last_undo = get_current_map_context().last_undo_action();
1433  if (dragging_left_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(1)) != 0) {
1434  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
1435  a = get_mouse_action().drag_left(*gui_, x, y, partial, last_undo);
1436  } else if (dragging_right_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(3)) != 0) {
1437  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
1438  a = get_mouse_action().drag_right(*gui_, x, y, partial, last_undo);
1439  }
1440  //Partial means that the mouse action has modified the
1441  //last undo action and the controller shouldn't add
1442  //anything to the undo stack (hence a different perform_ call)
1443  if (a != nullptr) {
1444  if (partial) {
1446  } else {
1448  }
1449  context_manager_->refresh_after_action(true);
1450  }
1451  } else {
1452  get_mouse_action().move(*gui_, hex_clicked);
1453  }
1454  gui().highlight_hex(hex_clicked);
1455 }
1456 
1457 void editor_controller::touch_motion(int /* x */, int /* y */, const bool /* browse */, bool /* update */, map_location /* new_loc */)
1458 {
1459  // Not implemented at all. Sorry, it's a very low priority for iOS port.
1460 }
1461 
1463 {
1464  return get_current_map_context().map().on_board_with_border(gui().hex_clicked_on(x,y));
1465 }
1466 
1467 bool editor_controller::right_click_show_menu(int /*x*/, int /*y*/, const bool /*browse*/)
1468 {
1470 }
1471 
1472 bool editor_controller::left_click(int x, int y, const bool browse)
1473 {
1474  toolkit_->clear_mouseover_overlay();
1475  if (mouse_handler_base::left_click(x, y, browse))
1476  return true;
1477 
1478  LOG_ED << "Left click, after generic handling";
1479  map_location hex_clicked = gui().hex_clicked_on(x, y);
1480  if (!get_current_map_context().map().on_board_with_border(hex_clicked))
1481  return true;
1482 
1483  LOG_ED << "Left click action " << hex_clicked;
1484  auto a = get_mouse_action().click_left(*gui_, x, y);
1485  if(a) {
1486  perform_refresh_delete(std::move(a), true);
1487  set_button_state();
1488  }
1489 
1490  return false;
1491 }
1492 
1493 void editor_controller::left_drag_end(int x, int y, const bool /*browse*/)
1494 {
1495  auto a = get_mouse_action().drag_end_left(*gui_, x, y);
1496  perform_delete(std::move(a));
1497 }
1498 
1499 void editor_controller::left_mouse_up(int x, int y, const bool /*browse*/)
1500 {
1501  auto a = get_mouse_action().up_left(*gui_, x, y);
1502  if(a) {
1503  perform_delete(std::move(a));
1504  set_button_state();
1505  }
1506  toolkit_->set_mouseover_overlay();
1507  context_manager_->refresh_after_action();
1508 }
1509 
1510 bool editor_controller::right_click(int x, int y, const bool browse)
1511 {
1512  toolkit_->clear_mouseover_overlay();
1513  if (mouse_handler_base::right_click(x, y, browse)) return true;
1514  LOG_ED << "Right click, after generic handling";
1515  map_location hex_clicked = gui().hex_clicked_on(x, y);
1516  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return true;
1517  LOG_ED << "Right click action " << hex_clicked;
1518  auto a = get_mouse_action().click_right(*gui_, x, y);
1519  if(a) {
1520  perform_refresh_delete(std::move(a), true);
1521  set_button_state();
1522  }
1523  return false;
1524 }
1525 
1526 void editor_controller::right_drag_end(int x, int y, const bool /*browse*/)
1527 {
1528  auto a = get_mouse_action().drag_end_right(*gui_, x, y);
1529  perform_delete(std::move(a));
1530 }
1531 
1532 void editor_controller::right_mouse_up(int x, int y, const bool browse)
1533 {
1534  // Call base method to handle context menus.
1535  mouse_handler_base::right_mouse_up(x, y, browse);
1536 
1537  auto a = get_mouse_action().up_right(*gui_, x, y);
1538  if(a) {
1539  perform_delete(std::move(a));
1540  set_button_state();
1541  }
1542  toolkit_->set_mouseover_overlay();
1543  context_manager_->refresh_after_action();
1544 }
1545 
1547 {
1548  const map_location& loc = gui().mouseover_hex();
1549  if (get_current_map_context().map().on_board(loc) == false)
1550  return;
1551 
1554 }
1555 
1556 void editor_controller::process_keyup_event(const SDL_Event& event)
1557 {
1558  auto a = get_mouse_action().key_event(gui(), event);
1559  perform_refresh_delete(std::move(a));
1560  toolkit_->set_mouseover_overlay();
1561 }
1562 
1564  return this;
1565 }
1566 
1568 {
1570 }
1571 
1573 {
1575 }
1576 
1578 {
1580 }
1581 
1583 {
1585 }
1586 
1588 {
1589  return toolkit_->get_palette_manager()->active_palette().action_pressed();
1590 }
1591 
1592 } //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:89
void toggle_debug_flag(DEBUG_FLAG flag)
Definition: display.hpp:951
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:539
virtual void highlight_hex(map_location hex)
Definition: display.cpp:1483
@ DEBUG_COORDINATES
Overlays x,y coords on tiles.
Definition: display.hpp:923
@ DEBUG_NUM_BITMAPS
Overlays number of bitmaps on tiles.
Definition: display.hpp:929
@ DEBUG_TERRAIN_CODES
Overlays terrain codes on tiles.
Definition: display.hpp:926
void invalidate_all()
Function to invalidate all tiles.
Definition: display.cpp:3125
surface screenshot(bool map_screenshot=false)
Capture a (map-)screenshot into a surface.
Definition: display.cpp:734
void queue_rerender()
Marks everything for rendering including all tiles and sidebar.
Definition: display.cpp:2291
void set_debug_flag(DEBUG_FLAG flag, bool value)
Definition: display.hpp:946
const map_location & mouseover_hex() const
Definition: display.hpp:305
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: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:37
void write()
Write the cfg file.
Definition: edit_unit.cpp:1042
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:965
#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:202
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_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: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 b