The Battle for Wesnoth  1.19.1+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 "editor/action/action.hpp"
24 
27 
29 
31 
36 #include "gui/dialogs/message.hpp"
40 #include "wml_exception.hpp"
41 
42 #include "resources.hpp"
43 #include "reports.hpp"
44 
45 #include "cursor.hpp"
46 #include "desktop/clipboard.hpp"
47 #include "floating_label.hpp"
48 #include "gettext.hpp"
49 #include "picture.hpp"
50 #include "sound.hpp"
51 #include "units/unit.hpp"
53 #include "quit_confirmation.hpp"
54 #include "sdl/input.hpp" // get_mouse_button_mask
55 
56 #include <functional>
57 
58 namespace {
59 static std::vector<std::string> saved_windows_;
60 }
61 
62 namespace editor {
63 
65 
67  : controller_base()
68  , mouse_handler_base()
69  , quit_confirmation(std::bind(&editor_controller::quit_confirm, this))
70  , active_menu_(editor::MAP)
71  , reports_(new reports())
72  , gui_(new editor_display(*this, *reports_))
73  , tods_()
74  , context_manager_(new context_manager(*gui_.get(), game_config_, clear_id ? "" : editor_controller::current_addon_id_))
75  , toolkit_(nullptr)
76  , tooltip_manager_()
77  , floating_label_manager_(nullptr)
78  , help_manager_(nullptr)
79  , do_quit_(false)
80  , quit_mode_(EXIT_ERROR)
81  , music_tracks_()
82 {
83  if(clear_id) {
85  }
86 
87  init_gui();
88  toolkit_.reset(new editor_toolkit(*gui_.get(), key_, game_config_, *context_manager_.get()));
90  context_manager_->locs_ = toolkit_->get_palette_manager()->location_palette_.get();
91  context_manager_->switch_context(0, true);
96 
97  gui().queue_rerender();
98 }
99 
101 {
102  gui_->change_display_context(&get_current_map_context());
103  gui_->add_redraw_observer(std::bind(&editor_controller::display_redraw_callback, this, std::placeholders::_1));
105  gui().set_debug_flag(display::DEBUG_COORDINATES, prefs::get().editor_draw_hex_coordinates());
106  gui().set_debug_flag(display::DEBUG_TERRAIN_CODES, prefs::get().editor_draw_terrain_codes());
107  gui().set_debug_flag(display::DEBUG_NUM_BITMAPS, prefs::get().editor_draw_num_of_bitmaps());
108 // halo_manager_.reset(new halo::manager(*gui_));
109 // resources::halo = halo_manager_.get();
110 // ^ These lines no longer necessary, the gui owns its halo manager.
111 // TODO: Should the editor map contexts actually own the halo manager and swap them in and out from the gui?
112 // 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
113 // without deleting it.
114 }
115 
117 {
118  for (const config &schedule : game_config.child_range("editor_times")) {
119 
120  const std::string& schedule_id = schedule["id"];
121  /* Use schedule id as the name if schedule name is empty */
122  const std::string& schedule_name = schedule["name"].empty() ? schedule["id"] : schedule["name"];
123  if (schedule_id.empty()) {
124  ERR_ED << "Missing ID attribute in a TOD Schedule.";
125  continue;
126  }
127 
128  tods_map::iterator times = tods_.find(schedule_id);
129  if (times == tods_.end()) {
130  std::pair<tods_map::iterator, bool> new_times =
131  tods_.emplace(schedule_id, std::pair(schedule_name, std::vector<time_of_day>()));
132  times = new_times.first;
133  } else {
134  ERR_ED << "Duplicate TOD Schedule identifiers.";
135  continue;
136  }
137 
138  for (const config &time : schedule.child_range("time")) {
139  times->second.second.emplace_back(time);
140  }
141 
142  }
143 
144  if (tods_.empty()) {
145  ERR_ED << "No editor time-of-day defined";
146  }
147 }
148 
150 {
151  const std::string tag_name = "editor_music";
152  if (game_config.child_range(tag_name).size() == 0) {
153  ERR_ED << "No editor music defined";
154  }
155  else {
156  for (const config& editor_music : game_config.child_range(tag_name)) {
157  for (const config& music : editor_music.child_range("music")) {
158  sound::music_track track(music);
159  if (track.file_path().empty())
160  WRN_ED << "Music track " << track.id() << " not found.";
161  else
162  music_tracks_.emplace_back(music);
163  }
164  }
165  }
166 }
167 
169 {
170  resources::tod_manager = nullptr;
171  resources::filter_con = nullptr;
172 
173  resources::classification = nullptr;
174 }
175 
177 {
178  try {
179  while (!do_quit_) {
180  play_slice();
181  }
182  } catch (const editor_exception& e) {
183  gui2::show_transient_message(_("Fatal error"), e.what());
184  return EXIT_ERROR;
185  } catch (const wml_exception& e) {
186  e.show();
187  }
188  return quit_mode_;
189 }
190 
192 }
193 
194 void editor_controller::do_screenshot(const std::string& screenshot_filename /* = "map_screenshot.png" */)
195 {
196  try {
197  surface screenshot = gui().screenshot(true);
198  if(!screenshot || image::save_image(screenshot, screenshot_filename) != image::save_result::success) {
199  ERR_ED << "Screenshot creation failed!";
200  }
201  } catch (const wml_exception& e) {
202  e.show();
203  }
204 }
205 
207 {
208  std::string modified;
209  std::size_t amount = context_manager_->modified_maps(modified);
210 
211  std::string message;
212  if (amount == 0) {
213  message = _("Do you really want to quit?");
214  } else if (amount == 1 && get_current_map_context().modified()) {
215  message = _("Do you really want to quit? Changes to this map since the last save will be lost.");
216  } else {
217  message = _("Do you really want to quit? The following maps were modified and all changes since the last save will be lost:");
218  message += "\n" + modified;
219  }
220  return quit_confirmation::show_prompt(message);
221 }
222 
224 {
226  if (unit_dlg.show()) {
227  unit_dlg.write();
228  }
229 }
230 
232 {
233  if (tods_.empty()) {
234  gui2::show_error_message(_("No editor time-of-day found."));
235  return;
236  }
237 
239  std::vector<time_of_day> prev_schedule = manager.times();
240 
241  gui2::dialogs::custom_tod tod_dlg(manager.times(), manager.get_current_time());
242 
243  /* Register callback to the dialog so that the map changes can be
244  * previewed in real time.
245  */
246  std::function<void(std::vector<time_of_day>)> update_func(
247  std::bind(
249  this,
250  std::placeholders::_1));
251  tod_dlg.register_callback(update_func);
252 
253  /* Autogenerate schedule id */
254  // TODO : sch_name should be translatable
255  std::int64_t current_millis = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
256  std::string sch_id = current_addon_id_+"-schedule";
257  std::string sch_name;
258 
259  // TODO : Needs better error handling
260  /* Show dialog and update current schedule */
261  if(tod_dlg.show()) {
262  /* Save the new schedule */
263  std::vector<time_of_day> schedule = tod_dlg.get_schedule();
264  if(!gui2::dialogs::tod_new_schedule::execute(sch_id, sch_name)) {
265  /* User pressed Cancel. Restore old schedule */
266  update_map_schedule(prev_schedule);
267  return;
268  }
269 
270  /* In case the ID or Name field is blank and user presses OK */
271  if (sch_id.empty()) {
272  sch_id = current_addon_id_+"-schedule-"+std::to_string(current_millis);
273  } else {
274  /* Check if the id entered is same as any of the existing ids
275  * If so, replace */
276  // TODO : Notify the user if they enter an already existing schedule ID
277  for (auto map_elem : tods_) {
278  if (sch_id == map_elem.first) {
279  sch_id = current_addon_id_+"-schedule-"+std::to_string(current_millis);
280  }
281  }
282  }
283 
284  tods_.emplace(sch_id, std::pair(sch_name, schedule));
286  get_current_map_context().save_schedule(sch_id, sch_name);
287  gui_->update_tod();
288  context_manager_->refresh_all();
289  } else {
290  /* Restore old schedule */
291  update_map_schedule(prev_schedule);
292  }
293 }
294 
295 void editor_controller::update_map_schedule(std::vector<time_of_day> schedule)
296 {
298  gui_->update_tod();
299  context_manager_->refresh_all();
300 }
301 
303 {
304  using namespace hotkey; //reduce hotkey:: clutter
305  int index = cmd.index;
306  switch(cmd.hotkey_command) {
307  case HOTKEY_NULL:
308  if (index >= 0) {
309  unsigned i = static_cast<unsigned>(index);
310 
311  switch (active_menu_) {
312  case editor::MAP:
313  if (i < context_manager_->open_maps()) {
314  return true;
315  }
316  return false;
317  case editor::LOAD_MRU:
318  case editor::PALETTE:
319  case editor::AREA:
320  case editor::ADDON:
321  case editor::SIDE:
322  case editor::TIME:
323  case editor::SCHEDULE:
325  case editor::MUSIC:
326  case editor::LOCAL_TIME:
327  case editor::UNIT_FACING:
328  return true;
329  }
330  }
331  return false;
333  return true;
335  return toolkit_->get_palette_manager()->can_scroll_up();
337  return toolkit_->get_palette_manager()->can_scroll_down();
338  case HOTKEY_ZOOM_IN:
339  return !gui_->zoom_at_max();
340  case HOTKEY_ZOOM_OUT:
341  return !gui_->zoom_at_min();
342  case HOTKEY_ZOOM_DEFAULT:
343  case HOTKEY_FULLSCREEN:
344  case HOTKEY_SCREENSHOT:
346  case HOTKEY_TOGGLE_GRID:
347  case HOTKEY_MOUSE_SCROLL:
348  case HOTKEY_ANIMATE_MAP:
349  case HOTKEY_MUTE:
350  case HOTKEY_PREFERENCES:
351  case HOTKEY_HELP:
352  case HOTKEY_QUIT_GAME:
353  case HOTKEY_SCROLL_UP:
354  case HOTKEY_SCROLL_DOWN:
355  case HOTKEY_SCROLL_LEFT:
356  case HOTKEY_SCROLL_RIGHT:
357  return true; //general hotkeys we can always do
358 
359  case HOTKEY_UNIT_LIST:
360  return !get_current_map_context().units().empty();
361 
362  case HOTKEY_STATUS_TABLE:
363  return !get_current_map_context().teams().empty();
364 
366  return gui().mouseover_hex().valid();
367 
368  // unit tool related
369  case HOTKEY_DELETE_UNIT:
370  case HOTKEY_RENAME_UNIT:
377  {
378  map_location loc = gui_->mouseover_hex();
379  const unit_map& units = get_current_map_context().units();
380  return (toolkit_->is_mouse_action_set(HOTKEY_EDITOR_TOOL_UNIT) &&
381  units.find(loc) != units.end());
382  }
383  case HOTKEY_UNDO:
385  case HOTKEY_REDO:
396  return true;
397 
398  // Only enable when editing a scenario
402 
403  case HOTKEY_EDITOR_PBL:
405  return true;
409 
412  return !get_current_map_context().teams().empty();
413 
414  // brushes
422 
424  return true;
426  return toolkit_->get_palette_manager()->active_palette().supports_swap();
430  {
431  std::string dummy;
432  return context_manager_->modified_maps(dummy) > 1;
433  }
439  return true;
441  return !get_current_map_context().get_filename().empty()
443 
444  // Tools
445  // Pure map editing tools this can be used all the time.
450  return true;
451  // WWL dependent tools which don't rely on defined sides.
458  return !get_current_map_context().teams().empty();
459 
463  return !get_current_map_context().is_pure_map() &&
465 
467  return !get_current_map_context().is_pure_map() &&
469  && !get_current_map_context().map().selection().empty();
470 
475  return !get_current_map_context().map().selection().empty()
476  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
478  return (get_current_map_context().map().selection().size() > 1
479  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE));
483  return !context_manager_->clipboard_empty();
488  return !context_manager_->clipboard_empty()
489  && toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
492  return !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
494  return !get_current_map_context().map().selection().empty()
496  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
513  return true;
517  return true;
518  default:
519  return false;
520  }
521 }
522 
524 {
525  using namespace hotkey;
526  int index = cmd.index;
527  switch (cmd.hotkey_command) {
528 
530  {
532  get_current_map_context().units().find(gui_->mouseover_hex());
533  return un->loyal() ? ACTION_ON : ACTION_OFF;
534 
535  }
537  {
539  get_current_map_context().units().find(gui_->mouseover_hex());
540  return un->can_recruit() ? ACTION_ON : ACTION_OFF;
541  }
543  {
545  get_current_map_context().units().find(gui_->mouseover_hex());
546  return (!un->unrenamable()) ? ACTION_ON : ACTION_OFF;
547  }
548  //TODO remove hardcoded hotkey names
550  return context_manager_->is_active_transitions_hotkey("editor-auto-update-transitions")
553  return context_manager_->is_active_transitions_hotkey("editor-partial-update-transitions")
556  return context_manager_->is_active_transitions_hotkey("editor-no-update-transitions")
559  return toolkit_->is_active_brush("brush-1") ? ACTION_ON : ACTION_OFF;
561  return toolkit_->is_active_brush("brush-2") ? ACTION_ON : ACTION_OFF;
563  return toolkit_->is_active_brush("brush-3") ? ACTION_ON : ACTION_OFF;
565  return toolkit_->is_active_brush("brush-nw-se") ? ACTION_ON : ACTION_OFF;
567  return toolkit_->is_active_brush("brush-sw-ne") ? ACTION_ON : ACTION_OFF;
568 
569  case HOTKEY_TOGGLE_GRID:
570  return prefs::get().grid() ? ACTION_ON : ACTION_OFF;
575  return get_current_map_context().map().selection().empty() ?
586  return toolkit_->is_mouse_action_set(cmd.hotkey_command) ? ACTION_ON : ACTION_OFF;
588  return gui_->debug_flag_set(display::DEBUG_COORDINATES) ? ACTION_ON : ACTION_OFF;
590  return gui_->debug_flag_set(display::DEBUG_TERRAIN_CODES) ? ACTION_ON : ACTION_OFF;
592  return gui_->debug_flag_set(display::DEBUG_NUM_BITMAPS) ? ACTION_ON : ACTION_OFF;
593 
595  return (prefs::get().minimap_draw_villages()) ? ACTION_ON : ACTION_OFF;
597  return (prefs::get().minimap_movement_coding()) ? ACTION_ON : ACTION_OFF;
599  return (prefs::get().minimap_terrain_coding()) ? ACTION_ON : ACTION_OFF;
601  return (prefs::get().minimap_draw_units()) ? ACTION_ON : ACTION_OFF;
603  return (prefs::get().minimap_draw_terrain()) ? ACTION_ON : ACTION_OFF;
604  case HOTKEY_ZOOM_DEFAULT:
605  return (gui_->get_zoom_factor() == 1.0) ? ACTION_ON : ACTION_OFF;
606 
607  case HOTKEY_NULL:
608  switch (active_menu_) {
609  case editor::MAP:
610  return index == context_manager_->current_context_index()
612  case editor::LOAD_MRU:
613  return ACTION_STATELESS;
614  case editor::PALETTE:
615  return ACTION_STATELESS;
616  case editor::AREA:
619  case editor::ADDON:
620  return ACTION_STATELESS;
621  case editor::SIDE:
622  return static_cast<std::size_t>(index) == gui_->playing_team()
624  case editor::TIME:
627  case editor::LOCAL_TIME:
629  get_current_map_context().get_active_area())
631  case editor::MUSIC:
633  ? ACTION_ON : ACTION_OFF;
634  case editor::SCHEDULE:
635  {
636  tods_map::const_iterator it = tods_.begin();
637  std::advance(it, index);
638  const std::vector<time_of_day>& times1 = it->second.second;
639  const std::vector<time_of_day>& times2 = get_current_map_context().get_time_manager()->times();
640  return (times1 == times2) ? ACTION_SELECTED : ACTION_DESELECTED;
641  }
643  {
644  tods_map::const_iterator it = tods_.begin();
645  std::advance(it, index);
646  const std::vector<time_of_day>& times1 = it->second.second;
647  int active_area = get_current_map_context().get_active_area();
648  const std::vector<time_of_day>& times2 = get_current_map_context().get_time_manager()->times(active_area);
649  return (times1 == times2) ? ACTION_SELECTED : ACTION_DESELECTED;
650  }
651  case editor::UNIT_FACING:
652  {
654  assert(un != get_current_map_context().units().end());
655  return un->facing() == index ? ACTION_SELECTED : ACTION_DESELECTED;
656  }
657  }
658  return ACTION_ON;
659  default:
660  return command_executor::get_action_state(cmd);
661  }
662 }
663 
664 bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool press, bool release)
665 {
666  using namespace hotkey;
667  HOTKEY_COMMAND command = cmd.hotkey_command;
668  SCOPE_ED;
669  int index = cmd.index;
670 
671  // nothing here handles release; fall through to base implementation
672  if (!press) {
673  return command_executor::do_execute_command(cmd, press, release);
674  }
675 
676  switch (command) {
677  case HOTKEY_NULL:
678  switch (active_menu_) {
679  case MAP:
680  if (index >= 0) {
681  unsigned i = static_cast<unsigned>(index);
682  if (i < context_manager_->size()) {
683  context_manager_->switch_context(index);
684  toolkit_->hotkey_set_mouse_action(HOTKEY_EDITOR_TOOL_PAINT);
685  return true;
686  }
687  }
688  return false;
689  case LOAD_MRU:
690  if (index >= 0) {
691  context_manager_->load_mru_item(static_cast<unsigned>(index));
692  }
693  return true;
694  case PALETTE:
695  toolkit_->get_palette_manager()->set_group(index);
696  return true;
697  case SIDE:
698  gui_->set_team(index, true);
699  gui_->set_playing_team(index);
700  toolkit_->get_palette_manager()->draw_contents();
701  return true;
702  case AREA:
703  {
705  const std::set<map_location>& area =
707  std::vector<map_location> locs(area.begin(), area.end());
709  gui_->scroll_to_tiles(locs.begin(), locs.end());
710  return true;
711  }
712  case ADDON:
713  return true;
714  case TIME:
715  {
717  gui_->update_tod();
718  return true;
719  }
720  case LOCAL_TIME:
721  {
723  return true;
724  }
725  case MUSIC:
726  {
727  //TODO mark the map as changed
730  std::vector<config> items;
731  items.emplace_back("id", "editor-playlist");
732  std::shared_ptr<gui::button> b = gui_->find_menu_button("menu-playlist");
733  show_menu(items, b->location().x +1, b->location().y + b->height() +1, false, *gui_);
734  return true;
735  }
736  case SCHEDULE:
737  {
738  tods_map::iterator iter = tods_.begin();
739  std::advance(iter, index);
740  get_current_map_context().replace_schedule(iter->second.second);
741  // TODO: test again after the assign-schedule menu is fixed. Should work, though.
742  gui_->update_tod();
743  return true;
744  }
745  case LOCAL_SCHEDULE:
746  {
747  tods_map::iterator iter = tods_.begin();
748  std::advance(iter, index);
749  get_current_map_context().replace_local_schedule(iter->second.second);
750  return true;
751  }
752  case UNIT_FACING:
753  {
755  assert(un != get_current_map_context().units().end());
756  un->set_facing(map_location::DIRECTION(index));
757  un->anim_comp().set_standing();
758  return true;
759  }
760  }
761  return true;
762 
763  //Zoom
764  case HOTKEY_ZOOM_IN:
765  gui_->set_zoom(true);
767  toolkit_->set_mouseover_overlay(*gui_);
768  return true;
769  case HOTKEY_ZOOM_OUT:
770  gui_->set_zoom(false);
772  toolkit_->set_mouseover_overlay(*gui_);
773  return true;
774  case HOTKEY_ZOOM_DEFAULT:
775  gui_->toggle_default_zoom();
777  toolkit_->set_mouseover_overlay(*gui_);
778  return true;
779 
780  //Palette
782  //TODO this code waits for the gui2 dialog to get ready
783  // std::vector< std::pair< std::string, std::string >> blah_items;
784  // toolkit_->get_palette_manager()->active_palette().expand_palette_groups_menu(blah_items);
785  // int selected = 1; //toolkit_->get_palette_manager()->active_palette().get_selected;
786  // gui2::teditor_select_palette_group::execute(selected, blah_items);
787  return true;
789  toolkit_->get_palette_manager()->scroll_up();
790  return true;
792  toolkit_->get_palette_manager()->scroll_down();
793  return true;
794 
795  case HOTKEY_QUIT_GAME:
797  do_quit_ = true;
799  }
800  return true;
803  return true;
805  context_manager_->save_all_maps(true);
806  do_quit_ = true;
808  return true;
811  return true;
814  return true;
816  toolkit_->get_palette_manager()->active_palette().swap();
817  return true;
819  if (dynamic_cast<const editor_action_chain*>(get_current_map_context().last_undo_action()) != nullptr) {
821  context_manager_->refresh_after_action();
822  } else {
823  undo();
824  }
825  return true;
826 
827  //Tool Selection
836  toolkit_->hotkey_set_mouse_action(command);
837  return true;
838 
839  case HOTKEY_EDITOR_PBL:
840  if(current_addon_id_ == "") {
842  context_manager_->set_addon_id(current_addon_id_);
843  }
844 
845  if(current_addon_id_ != "") {
846  context_manager_->edit_pbl();
847  }
848  return true;
849 
851  if(current_addon_id_ == "") {
853  context_manager_->set_addon_id(current_addon_id_);
854  }
855 
856  if(current_addon_id_ != "") {
857  context_manager_->change_addon_id();
858  }
859  return true;
860 
862  add_area();
863  return true;
864 
866  change_unit_id();
867  return true;
868 
869  return true;
871  {
872  map_location loc = gui_->mouseover_hex();
874  bool unrenamable = un->unrenamable();
875  un->set_unrenamable(!unrenamable);
876  }
877  return true;
879  {
880  map_location loc = gui_->mouseover_hex();
882  bool canrecruit = un->can_recruit();
883  un->set_can_recruit(!canrecruit);
884  un->anim_comp().set_standing();
885  }
886  return true;
887  case HOTKEY_DELETE_UNIT:
888  {
889  map_location loc = gui_->mouseover_hex();
890  perform_delete(std::make_unique<editor_action_unit_delete>(loc));
891  }
892  return true;
893  case HOTKEY_EDITOR_CLIPBOARD_PASTE: //paste is somewhat different as it might be "one action then revert to previous mode"
894  toolkit_->hotkey_set_mouse_action(command);
895  return true;
896 
897  //Clipboard
899  context_manager_->get_clipboard().rotate_60_cw();
900  toolkit_->update_mouse_action_highlights();
901  return true;
903  context_manager_->get_clipboard().rotate_60_ccw();
904  toolkit_->update_mouse_action_highlights();
905  return true;
907  context_manager_->get_clipboard().flip_horizontal();
908  toolkit_->update_mouse_action_highlights();
909  return true;
911  context_manager_->get_clipboard().flip_vertical();
912  toolkit_->update_mouse_action_highlights();
913  return true;
914 
915  //Brushes
917  toolkit_->cycle_brush();
918  return true;
920  toolkit_->set_brush("brush-1");
921  return true;
923  toolkit_->set_brush("brush-2");
924  return true;
926  toolkit_->set_brush("brush-3");
927  return true;
929  toolkit_->set_brush("brush-nw-se");
930  return true;
932  toolkit_->set_brush("brush-sw-ne");
933  return true;
934 
936  copy_selection();
937  return true;
939  cut_selection();
940  return true;
942  context_manager_->rename_area_dialog();
943  return true;
945  save_area();
946  return true;
949  return true;
951  if(!get_current_map_context().map().everything_selected()) {
952  context_manager_->perform_refresh(editor_action_select_all());
953  return true;
954  }
955  [[fallthrough]];
958  return true;
960  context_manager_->perform_refresh(editor_action_select_none());
961  return true;
963  context_manager_->fill_selection();
964  return true;
967  get_current_map_context().map().selection()));
968  return true;
969 
971  context_manager_->edit_scenario_dialog();
972  return true;
973 
976  get_current_map_context().get_active_area());
977  return true;
978 
979  // map specific
981  context_manager_->close_current_context();
982  // Copy behaviour from when switching windows to always reset the active tool to the Paint Tool
983  // This avoids the situation of having a scenario-specific tool active in a map context which can cause a crash if used
984  // Not elegant but at least avoids a potential crash and is consistent with existing behaviour
985  toolkit_->hotkey_set_mouse_action(HOTKEY_EDITOR_TOOL_PAINT);
986  return true;
988  context_manager_->load_map_dialog();
989  return true;
991  context_manager_->revert_map();
992  return true;
994  context_manager_->new_map_dialog();
995  return true;
997  if(current_addon_id_ == "") {
999  context_manager_->set_addon_id(current_addon_id_);
1000  }
1001 
1002  if(current_addon_id_ != "") {
1003  context_manager_->new_scenario_dialog();
1004  }
1005  return true;
1007  save_map();
1008  return true;
1010  context_manager_->save_all_maps();
1011  return true;
1013  context_manager_->save_map_as_dialog();
1014  return true;
1016  if(current_addon_id_ == "") {
1018  context_manager_->set_addon_id(current_addon_id_);
1019  }
1020 
1021  if(current_addon_id_ != "") {
1022  context_manager_->save_scenario_as_dialog();
1023  }
1024  return true;
1026  context_manager_->generate_map_dialog();
1027  return true;
1029  context_manager_->apply_mask_dialog();
1030  return true;
1032  context_manager_->create_mask_to_dialog();
1033  return true;
1035  context_manager_->resize_map_dialog();
1036  return true;
1037 
1038  // Side specific ones
1040  if(get_current_map_context().teams().size() >= 9) {
1041  size_t new_side_num = get_current_map_context().teams().size() + 1;
1042  toolkit_->get_palette_manager()->location_palette_->add_item(std::to_string(new_side_num));
1043  }
1045  gui_->init_flags();
1046  return true;
1048  gui_->set_team(0, true);
1049  gui_->set_playing_team(0);
1051  return true;
1053  context_manager_->edit_side_dialog(gui_->viewing_team());
1054  return true;
1055 
1056  // Transitions
1058  context_manager_->set_update_transitions_mode(2);
1059  return true;
1061  context_manager_->set_update_transitions_mode(1);
1062  return true;
1064  context_manager_->set_update_transitions_mode(0);
1065  return true;
1067  if(context_manager_->toggle_update_transitions()) {
1068  return true;
1069  }
1070  [[fallthrough]];
1072  context_manager_->refresh_all();
1073  return true;
1074  // Refresh
1075  case HOTKEY_EDITOR_REFRESH:
1076  context_manager_->reload_map();
1077  return true;
1080  return true;
1081 
1085  gui().invalidate_all();
1086  return true;
1090  gui().invalidate_all();
1091  return true;
1095  gui().invalidate_all();
1096  return true;
1098  location_palette* lp = dynamic_cast<location_palette*>(&toolkit_->get_palette_manager()->active_palette());
1099  if (lp) {
1100  perform_delete(std::make_unique<editor_action_starting_position>(map_location(), lp->selected_item()));
1101  // No idea if this is the right thing to call, but it ensures starting
1102  // position labels get removed on delete.
1103  context_manager_->refresh_after_action();
1104  }
1105  return true;
1106  }
1107  default:
1108  return hotkey::command_executor::do_execute_command(cmd, press, release);
1109  }
1110 }
1111 
1113 {
1114  help::show_help("..editor");
1115 }
1116 
1117 void editor_controller::show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& disp)
1118 {
1119  if(context_menu) {
1120  if(!get_current_map_context().map().on_board_with_border(gui().hex_clicked_on(xloc, yloc))) {
1121  return;
1122  }
1123  }
1124 
1125  std::vector<config> items;
1126  for(const auto& c : items_arg) {
1127  const std::string& id = c["id"];
1128 
1130 
1131  if((can_execute_command(cmd) && (!context_menu || in_context_menu(cmd)))
1133  {
1134  items.emplace_back("id", id);
1135  }
1136  }
1137 
1138  // No point in showing an empty menu.
1139  if(items.empty()) {
1140  return;
1141  }
1142 
1143  // Based on the ID of the first entry, we fill the menu contextually.
1144  const std::string& first_id = items.front()["id"];
1145 
1146  if(first_id == "EDITOR-LOAD-MRU-PLACEHOLDER") {
1148  context_manager_->expand_load_mru_menu(items, 0);
1149  }
1150 
1151  if(first_id == "editor-switch-map") {
1153  context_manager_->expand_open_maps_menu(items, 0);
1154  }
1155 
1156  if(first_id == "editor-palette-groups") {
1158  toolkit_->get_palette_manager()->active_palette().expand_palette_groups_menu(items, 0);
1159  }
1160 
1161  if(first_id == "editor-switch-side") {
1163  context_manager_->expand_sides_menu(items, 0);
1164  }
1165 
1166  if(first_id == "editor-switch-area") {
1168  context_manager_->expand_areas_menu(items, 0);
1169  }
1170 
1171  if(first_id == "editor-pbl") {
1173  }
1174 
1175  if(!items.empty() && items.front()["id"] == "editor-switch-time") {
1177  context_manager_->expand_time_menu(items, 0);
1178  }
1179 
1180  if(first_id == "editor-assign-local-time") {
1182  context_manager_->expand_local_time_menu(items, 0);
1183  }
1184 
1185  if(first_id == "menu-unit-facings") {
1187  auto pos = items.erase(items.begin());
1188  int dir = 0;
1189  std::generate_n(std::inserter<std::vector<config>>(items, pos), static_cast<int>(map_location::NDIRECTIONS), [&dir]() -> config {
1191  });
1192  }
1193 
1194  if(first_id == "editor-playlist") {
1196  auto pos = items.erase(items.begin());
1197  std::transform(music_tracks_.begin(), music_tracks_.end(), std::inserter<std::vector<config>>(items, pos), [](const sound::music_track& track) -> config {
1198  return config {"label", track.title().empty() ? track.id() : track.title()};
1199  });
1200  }
1201 
1202  if(first_id == "editor-assign-schedule") {
1204  auto pos = items.erase(items.begin());
1205  std::transform(tods_.begin(), tods_.end(), std::inserter<std::vector<config>>(items, pos), [](const tods_map::value_type& tod) -> config {
1206  return config {"label", tod.second.first};
1207  });
1208  }
1209 
1210  if(first_id == "editor-assign-local-schedule") {
1212  auto pos = items.erase(items.begin());
1213  std::transform(tods_.begin(), tods_.end(), std::inserter<std::vector<config>>(items, pos), [](const tods_map::value_type& tod) -> config {
1214  return config {"label", tod.second.first};
1215  });
1216  }
1217 
1218  command_executor::show_menu(items, xloc, yloc, context_menu, disp);
1219 }
1220 
1222 {
1223  gui_->clear_help_string();
1224  gui2::dialogs::preferences_dialog::display();
1225 
1226  gui_->queue_rerender();
1227 }
1228 
1230 {
1231  prefs::get().set_grid(!prefs::get().grid());
1232  gui_->invalidate_all();
1233 }
1234 
1236 {
1237  map_location loc = gui_->mouseover_hex();
1238  const unit_map & units = get_current_map_context().units();
1239  const unit_map::const_unit_iterator un = units.find(loc);
1240  if(un != units.end()) {
1241  help::show_unit_help(un->type_id(), un->type().show_variations_in_help(), false);
1242  } else {
1243  help::show_help("..units");
1244  }
1245 }
1246 
1247 
1249 {
1250  if (!get_current_map_context().map().selection().empty()) {
1251  context_manager_->get_clipboard() = map_fragment(get_current_map_context().map(), get_current_map_context().map().selection());
1252  context_manager_->get_clipboard().center_by_mass();
1253  }
1254 }
1255 
1257 {
1258  map_location loc = gui_->mouseover_hex();
1259  unit_map& units = get_current_map_context().units();
1260  const unit_map::unit_iterator& un = units.find(loc);
1261 
1262  const std::string title(N_("Change Unit ID"));
1263  const std::string label(N_("ID:"));
1264 
1265  if(un != units.end()) {
1266  std::string id = un->id();
1267  if (gui2::dialogs::edit_text::execute(title, label, id)) {
1268  un->set_id(id);
1269  }
1270  }
1271 }
1272 
1274 {
1275  map_location loc = gui_->mouseover_hex();
1276  unit_map& units = get_current_map_context().units();
1277  const unit_map::unit_iterator& un = units.find(loc);
1278 
1279  const std::string title(N_("Rename Unit"));
1280  const std::string label(N_("Name:"));
1281 
1282  if(un != units.end()) {
1283  std::string name = un->name();
1284  if(gui2::dialogs::edit_text::execute(title, label, name)) {
1285  //TODO we may not want a translated name here.
1286  un->set_name(name);
1287  }
1288  }
1289 }
1290 
1292 {
1294 }
1295 
1297 {
1298  copy_selection();
1300 }
1301 
1303 {
1304  const std::set<map_location>& area = get_current_map_context().map().selection();
1306 }
1307 
1309 {
1310  const std::set<map_location>& area = get_current_map_context().map().selection();
1312 }
1313 
1315 {
1316  std::stringstream ssx, ssy;
1317  std::set<map_location>::const_iterator i = get_current_map_context().map().selection().begin();
1318  if (i != get_current_map_context().map().selection().end()) {
1319  ssx << "x = " << i->wml_x();
1320  ssy << "y = " << i->wml_y();
1321  ++i;
1322  while (i != get_current_map_context().map().selection().end()) {
1323  ssx << ", " << i->wml_x();
1324  ssy << ", " << i->wml_y();
1325  ++i;
1326  }
1327  ssx << "\n" << ssy.str() << "\n";
1328  desktop::clipboard::copy_to_clipboard(ssx.str(), false);
1329  }
1330 }
1331 
1332 void editor_controller::perform_delete(std::unique_ptr<editor_action> action)
1333 {
1334  if (action) {
1336  }
1337 }
1338 
1339 void editor_controller::perform_refresh_delete(std::unique_ptr<editor_action> action, bool drag_part /* =false */)
1340 {
1341  if (action) {
1342  context_manager_->perform_refresh(*action, drag_part);
1343  }
1344 }
1345 
1347 {
1349  context_manager_->refresh_all();
1350 }
1351 
1353 {
1354  set_button_state();
1355  toolkit_->adjust_size();
1357 }
1358 
1360 {
1362  context_manager_->refresh_after_action();
1363 }
1364 
1366 {
1368  context_manager_->refresh_after_action();
1369 }
1370 
1371 void editor_controller::mouse_motion(int x, int y, const bool /*browse*/,
1372  bool update, map_location /*new_loc*/)
1373 {
1374  if (mouse_handler_base::mouse_motion_default(x, y, update)) return;
1375  map_location hex_clicked = gui().hex_clicked_on(x, y);
1376  if (get_current_map_context().map().on_board_with_border(drag_from_hex_) && is_dragging()) {
1377  std::unique_ptr<editor_action> a;
1378  bool partial = false;
1379  // last_undo is a non-owning pointer. Although it could have other uses, it seems to be
1380  // mainly (only?) used for printing debugging information.
1381  auto last_undo = get_current_map_context().last_undo_action();
1382  if (dragging_left_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(1)) != 0) {
1383  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
1384  a = get_mouse_action().drag_left(*gui_, x, y, partial, last_undo);
1385  } else if (dragging_right_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(3)) != 0) {
1386  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
1387  a = get_mouse_action().drag_right(*gui_, x, y, partial, last_undo);
1388  }
1389  //Partial means that the mouse action has modified the
1390  //last undo action and the controller shouldn't add
1391  //anything to the undo stack (hence a different perform_ call)
1392  if (a != nullptr) {
1393  if (partial) {
1395  } else {
1397  }
1398  context_manager_->refresh_after_action(true);
1399  }
1400  } else {
1401  get_mouse_action().move(*gui_, hex_clicked);
1402  }
1403  gui().highlight_hex(hex_clicked);
1404 }
1405 
1406 void editor_controller::touch_motion(int /* x */, int /* y */, const bool /* browse */, bool /* update */, map_location /* new_loc */)
1407 {
1408  // Not implemented at all. Sorry, it's a very low priority for iOS port.
1409 }
1410 
1412 {
1413  return get_current_map_context().map().on_board_with_border(gui().hex_clicked_on(x,y));
1414 }
1415 
1416 bool editor_controller::right_click_show_menu(int /*x*/, int /*y*/, const bool /*browse*/)
1417 {
1419 }
1420 
1421 bool editor_controller::left_click(int x, int y, const bool browse)
1422 {
1423  toolkit_->clear_mouseover_overlay();
1424  if (mouse_handler_base::left_click(x, y, browse))
1425  return true;
1426 
1427  LOG_ED << "Left click, after generic handling";
1428  map_location hex_clicked = gui().hex_clicked_on(x, y);
1429  if (!get_current_map_context().map().on_board_with_border(hex_clicked))
1430  return true;
1431 
1432  LOG_ED << "Left click action " << hex_clicked;
1433  auto a = get_mouse_action().click_left(*gui_, x, y);
1434  if(a) {
1435  perform_refresh_delete(std::move(a), true);
1436  set_button_state();
1437  }
1438 
1439  return false;
1440 }
1441 
1442 void editor_controller::left_drag_end(int x, int y, const bool /*browse*/)
1443 {
1444  auto a = get_mouse_action().drag_end_left(*gui_, x, y);
1445  perform_delete(std::move(a));
1446 }
1447 
1448 void editor_controller::left_mouse_up(int x, int y, const bool /*browse*/)
1449 {
1450  auto a = get_mouse_action().up_left(*gui_, x, y);
1451  if(a) {
1452  perform_delete(std::move(a));
1453  set_button_state();
1454  }
1455  toolkit_->set_mouseover_overlay();
1456  context_manager_->refresh_after_action();
1457 }
1458 
1459 bool editor_controller::right_click(int x, int y, const bool browse)
1460 {
1461  toolkit_->clear_mouseover_overlay();
1462  if (mouse_handler_base::right_click(x, y, browse)) return true;
1463  LOG_ED << "Right click, after generic handling";
1464  map_location hex_clicked = gui().hex_clicked_on(x, y);
1465  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return true;
1466  LOG_ED << "Right click action " << hex_clicked;
1467  auto a = get_mouse_action().click_right(*gui_, x, y);
1468  if(a) {
1469  perform_refresh_delete(std::move(a), true);
1470  set_button_state();
1471  }
1472  return false;
1473 }
1474 
1475 void editor_controller::right_drag_end(int x, int y, const bool /*browse*/)
1476 {
1477  auto a = get_mouse_action().drag_end_right(*gui_, x, y);
1478  perform_delete(std::move(a));
1479 }
1480 
1481 void editor_controller::right_mouse_up(int x, int y, const bool browse)
1482 {
1483  // Call base method to handle context menus.
1484  mouse_handler_base::right_mouse_up(x, y, browse);
1485 
1486  auto a = get_mouse_action().up_right(*gui_, x, y);
1487  if(a) {
1488  perform_delete(std::move(a));
1489  set_button_state();
1490  }
1491  toolkit_->set_mouseover_overlay();
1492  context_manager_->refresh_after_action();
1493 }
1494 
1496 {
1497  const map_location& loc = gui().mouseover_hex();
1498  if (get_current_map_context().map().on_board(loc) == false)
1499  return;
1500 
1503 }
1504 
1505 void editor_controller::process_keyup_event(const SDL_Event& event)
1506 {
1507  auto a = get_mouse_action().key_event(gui(), event);
1508  perform_refresh_delete(std::move(a));
1509  toolkit_->set_mouseover_overlay();
1510 }
1511 
1513  return this;
1514 }
1515 
1517 {
1519 }
1520 
1522 {
1524 }
1525 
1527 {
1529 }
1530 
1532 {
1534 }
1535 
1537 {
1538  return toolkit_->get_palette_manager()->active_palette().action_pressed();
1539 }
1540 
1541 } //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 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:319
void register_callback(std::function< void(std::vector< time_of_day >)>)
Register callback for update.
Definition: custom_tod.cpp:325
Dialog that allows user to create custom unit types.
Definition: edit_unit.hpp:38
void write()
Write the cfg file.
Definition: edit_unit.cpp:1043
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
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()
static std::vector< std::string > saved_windows_
std::string initialize_addon()
Definition: editor_main.cpp:31
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_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_TOOL_ITEM
@ TITLE_SCREEN__RELOAD_WML
@ HOTKEY_EDITOR_UNIT_TOGGLE_RENAMEABLE
@ HOTKEY_EDITOR_SCENARIO_EDIT
@ 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
const std::vector< std::string > items
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
@ 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