The Battle for Wesnoth  1.19.0-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 
30 #include "preferences/editor.hpp"
31 
35 #include "gui/dialogs/message.hpp"
39 #include "wml_exception.hpp"
40 
41 #include "resources.hpp"
42 #include "reports.hpp"
43 
44 #include "cursor.hpp"
45 #include "desktop/clipboard.hpp"
46 #include "floating_label.hpp"
47 #include "gettext.hpp"
48 #include "picture.hpp"
49 #include "sound.hpp"
50 #include "units/unit.hpp"
52 #include "quit_confirmation.hpp"
53 #include "sdl/input.hpp" // get_mouse_button_mask
54 
55 #include <functional>
56 
57 namespace {
58 static std::vector<std::string> saved_windows_;
59 }
60 
61 namespace editor {
62 
64 
66  : controller_base()
67  , mouse_handler_base()
68  , quit_confirmation(std::bind(&editor_controller::quit_confirm, this))
69  , active_menu_(editor::MAP)
70  , reports_(new reports())
71  , gui_(new editor_display(*this, *reports_))
72  , tods_()
73  , context_manager_(new context_manager(*gui_.get(), game_config_, clear_id ? "" : editor_controller::current_addon_id_))
74  , toolkit_(nullptr)
75  , tooltip_manager_()
76  , floating_label_manager_(nullptr)
77  , help_manager_(nullptr)
78  , do_quit_(false)
79  , quit_mode_(EXIT_ERROR)
80  , music_tracks_()
81 {
82  if(clear_id) {
84  }
85 
86  init_gui();
87  toolkit_.reset(new editor_toolkit(*gui_.get(), key_, game_config_, *context_manager_.get()));
89  context_manager_->locs_ = toolkit_->get_palette_manager()->location_palette_.get();
90  context_manager_->switch_context(0, true);
95 
96  gui().queue_rerender();
97 }
98 
100 {
101  gui_->change_display_context(&get_current_map_context());
102  gui_->add_redraw_observer(std::bind(&editor_controller::display_redraw_callback, this, std::placeholders::_1));
107 // halo_manager_.reset(new halo::manager(*gui_));
108 // resources::halo = halo_manager_.get();
109 // ^ These lines no longer necessary, the gui owns its halo manager.
110 // TODO: Should the editor map contexts actually own the halo manager and swap them in and out from the gui?
111 // 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
112 // without deleting it.
113 }
114 
116 {
117  for (const config &schedule : game_config.child_range("editor_times")) {
118 
119  const std::string& schedule_id = schedule["id"];
120  /* Use schedule id as the name if schedule name is empty */
121  const std::string& schedule_name = schedule["name"].empty() ? schedule["id"] : schedule["name"];
122  if (schedule_id.empty()) {
123  ERR_ED << "Missing ID attribute in a TOD Schedule.";
124  continue;
125  }
126 
127  tods_map::iterator times = tods_.find(schedule_id);
128  if (times == tods_.end()) {
129  std::pair<tods_map::iterator, bool> new_times =
130  tods_.emplace(schedule_id, std::pair(schedule_name, std::vector<time_of_day>()));
131  times = new_times.first;
132  } else {
133  ERR_ED << "Duplicate TOD Schedule identifiers.";
134  continue;
135  }
136 
137  for (const config &time : schedule.child_range("time")) {
138  times->second.second.emplace_back(time);
139  }
140 
141  }
142 
143  if (tods_.empty()) {
144  ERR_ED << "No editor time-of-day defined";
145  }
146 }
147 
149 {
150  const std::string tag_name = "editor_music";
151  if (game_config.child_range(tag_name).size() == 0) {
152  ERR_ED << "No editor music defined";
153  }
154  else {
155  for (const config& editor_music : game_config.child_range(tag_name)) {
156  for (const config& music : editor_music.child_range("music")) {
157  sound::music_track track(music);
158  if (track.file_path().empty())
159  WRN_ED << "Music track " << track.id() << " not found.";
160  else
161  music_tracks_.emplace_back(music);
162  }
163  }
164  }
165 }
166 
168 {
169  resources::tod_manager = nullptr;
170  resources::filter_con = nullptr;
171 
172  resources::classification = nullptr;
173 }
174 
176 {
177  try {
178  while (!do_quit_) {
179  play_slice();
180  }
181  } catch (const editor_exception& e) {
182  gui2::show_transient_message(_("Fatal error"), e.what());
183  return EXIT_ERROR;
184  } catch (const wml_exception& e) {
185  e.show();
186  }
187  return quit_mode_;
188 }
189 
191 }
192 
193 void editor_controller::do_screenshot(const std::string& screenshot_filename /* = "map_screenshot.png" */)
194 {
195  try {
196  surface screenshot = gui().screenshot(true);
197  if(!screenshot || image::save_image(screenshot, screenshot_filename) != image::save_result::success) {
198  ERR_ED << "Screenshot creation failed!";
199  }
200  } catch (const wml_exception& e) {
201  e.show();
202  }
203 }
204 
206 {
207  std::string modified;
208  std::size_t amount = context_manager_->modified_maps(modified);
209 
210  std::string message;
211  if (amount == 0) {
212  message = _("Do you really want to quit?");
213  } else if (amount == 1 && get_current_map_context().modified()) {
214  message = _("Do you really want to quit? Changes to this map since the last save will be lost.");
215  } else {
216  message = _("Do you really want to quit? The following maps were modified and all changes since the last save will be lost:");
217  message += "\n" + modified;
218  }
219  return quit_confirmation::show_prompt(message);
220 }
221 
223 {
224  if (tods_.empty()) {
225  gui2::show_error_message(_("No editor time-of-day found."));
226  return;
227  }
228 
230  std::vector<time_of_day> prev_schedule = manager.times();
231 
232  gui2::dialogs::custom_tod tod_dlg(manager.times(), manager.get_current_time());
233 
234  /* Register callback to the dialog so that the map changes can be
235  * previewed in real time.
236  */
237  std::function<void(std::vector<time_of_day>)> update_func(
238  std::bind(
240  this,
241  std::placeholders::_1));
242  tod_dlg.register_callback(update_func);
243 
244  /* Autogenerate schedule id */
245  // TODO : sch_name should be translatable
246  std::int64_t current_millis = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
247  std::string sch_id = current_addon_id_+"-schedule";
248  std::string sch_name;
249 
250  // TODO : Needs better error handling
251  /* Show dialog and update current schedule */
252  if(tod_dlg.show()) {
253  /* Save the new schedule */
254  std::vector<time_of_day> schedule = tod_dlg.get_schedule();
255  if(!gui2::dialogs::tod_new_schedule::execute(sch_id, sch_name)) {
256  /* User pressed Cancel. Restore old schedule */
257  update_map_schedule(prev_schedule);
258  return;
259  }
260 
261  /* In case the ID or Name field is blank and user presses OK */
262  if (sch_id.empty()) {
263  sch_id = current_addon_id_+"-schedule-"+std::to_string(current_millis);
264  } else {
265  /* Check if the id entered is same as any of the existing ids
266  * If so, replace */
267  // TODO : Notify the user if they enter an already existing schedule ID
268  for (auto map_elem : tods_) {
269  if (sch_id == map_elem.first) {
270  sch_id = current_addon_id_+"-schedule-"+std::to_string(current_millis);
271  }
272  }
273  }
274 
275  tods_.emplace(sch_id, std::pair(sch_name, schedule));
277  get_current_map_context().save_schedule(sch_id, sch_name);
278  gui_->update_tod();
279  context_manager_->refresh_all();
280  } else {
281  /* Restore old schedule */
282  update_map_schedule(prev_schedule);
283  }
284 }
285 
286 void editor_controller::update_map_schedule(std::vector<time_of_day> schedule)
287 {
289  gui_->update_tod();
290  context_manager_->refresh_all();
291 }
292 
294 {
295  using namespace hotkey; //reduce hotkey:: clutter
296  int index = cmd.index;
297  switch(cmd.hotkey_command) {
298  case HOTKEY_NULL:
299  if (index >= 0) {
300  unsigned i = static_cast<unsigned>(index);
301 
302  switch (active_menu_) {
303  case editor::MAP:
304  if (i < context_manager_->open_maps()) {
305  return true;
306  }
307  return false;
308  case editor::LOAD_MRU:
309  case editor::PALETTE:
310  case editor::AREA:
311  case editor::ADDON:
312  case editor::SIDE:
313  case editor::TIME:
314  case editor::SCHEDULE:
316  case editor::MUSIC:
317  case editor::LOCAL_TIME:
318  case editor::UNIT_FACING:
319  return true;
320  }
321  }
322  return false;
324  return true;
326  return toolkit_->get_palette_manager()->can_scroll_up();
328  return toolkit_->get_palette_manager()->can_scroll_down();
329  case HOTKEY_ZOOM_IN:
330  return !gui_->zoom_at_max();
331  case HOTKEY_ZOOM_OUT:
332  return !gui_->zoom_at_min();
333  case HOTKEY_ZOOM_DEFAULT:
334  case HOTKEY_FULLSCREEN:
335  case HOTKEY_SCREENSHOT:
337  case HOTKEY_TOGGLE_GRID:
338  case HOTKEY_MOUSE_SCROLL:
339  case HOTKEY_ANIMATE_MAP:
340  case HOTKEY_MUTE:
341  case HOTKEY_PREFERENCES:
342  case HOTKEY_HELP:
343  case HOTKEY_QUIT_GAME:
344  case HOTKEY_SCROLL_UP:
345  case HOTKEY_SCROLL_DOWN:
346  case HOTKEY_SCROLL_LEFT:
347  case HOTKEY_SCROLL_RIGHT:
348  return true; //general hotkeys we can always do
349 
350  case HOTKEY_UNIT_LIST:
351  return !get_current_map_context().units().empty();
352 
353  case HOTKEY_STATUS_TABLE:
354  return !get_current_map_context().teams().empty();
355 
357  return gui().mouseover_hex().valid();
358 
359  // unit tool related
360  case HOTKEY_DELETE_UNIT:
361  case HOTKEY_RENAME_UNIT:
368  {
369  map_location loc = gui_->mouseover_hex();
370  const unit_map& units = get_current_map_context().units();
371  return (toolkit_->is_mouse_action_set(HOTKEY_EDITOR_TOOL_UNIT) &&
372  units.find(loc) != units.end());
373  }
374  case HOTKEY_UNDO:
376  case HOTKEY_REDO:
387  return true;
388 
389  // Only enable when editing a scenario
392 
393  case HOTKEY_EDITOR_PBL:
395  return true;
399 
402  return !get_current_map_context().teams().empty();
403 
404  // brushes
412 
414  return true;
416  return toolkit_->get_palette_manager()->active_palette().supports_swap();
420  {
421  std::string dummy;
422  return context_manager_->modified_maps(dummy) > 1;
423  }
429  return true;
431  return !get_current_map_context().get_filename().empty()
433 
434  // Tools
435  // Pure map editing tools this can be used all the time.
440  return true;
441  // WWL dependent tools which don't rely on defined sides.
448  return !get_current_map_context().teams().empty();
449 
453  return !get_current_map_context().is_pure_map() &&
455 
457  return !get_current_map_context().is_pure_map() &&
459  && !get_current_map_context().map().selection().empty();
460 
465  return !get_current_map_context().map().selection().empty()
466  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
468  return (get_current_map_context().map().selection().size() > 1
469  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE));
473  return !context_manager_->clipboard_empty();
478  return !context_manager_->clipboard_empty()
479  && toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
482  return !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
484  return !get_current_map_context().map().selection().empty()
486  && !toolkit_->is_mouse_action_set(HOTKEY_EDITOR_CLIPBOARD_PASTE);
503  return true;
507  return true;
508  default:
509  return false;
510  }
511 }
512 
514 {
515  using namespace hotkey;
516  int index = cmd.index;
517  switch (cmd.hotkey_command) {
518 
520  {
522  get_current_map_context().units().find(gui_->mouseover_hex());
523  return un->loyal() ? ACTION_ON : ACTION_OFF;
524 
525  }
527  {
529  get_current_map_context().units().find(gui_->mouseover_hex());
530  return un->can_recruit() ? ACTION_ON : ACTION_OFF;
531  }
533  {
535  get_current_map_context().units().find(gui_->mouseover_hex());
536  return (!un->unrenamable()) ? ACTION_ON : ACTION_OFF;
537  }
538  //TODO remove hardcoded hotkey names
540  return context_manager_->is_active_transitions_hotkey("editor-auto-update-transitions")
543  return context_manager_->is_active_transitions_hotkey("editor-partial-update-transitions")
546  return context_manager_->is_active_transitions_hotkey("editor-no-update-transitions")
549  return toolkit_->is_active_brush("brush-1") ? ACTION_ON : ACTION_OFF;
551  return toolkit_->is_active_brush("brush-2") ? ACTION_ON : ACTION_OFF;
553  return toolkit_->is_active_brush("brush-3") ? ACTION_ON : ACTION_OFF;
555  return toolkit_->is_active_brush("brush-nw-se") ? ACTION_ON : ACTION_OFF;
557  return toolkit_->is_active_brush("brush-sw-ne") ? ACTION_ON : ACTION_OFF;
558 
559  case HOTKEY_TOGGLE_GRID:
565  return get_current_map_context().map().selection().empty() ?
576  return toolkit_->is_mouse_action_set(cmd.hotkey_command) ? ACTION_ON : ACTION_OFF;
578  return gui_->debug_flag_set(display::DEBUG_COORDINATES) ? ACTION_ON : ACTION_OFF;
580  return gui_->debug_flag_set(display::DEBUG_TERRAIN_CODES) ? ACTION_ON : ACTION_OFF;
582  return gui_->debug_flag_set(display::DEBUG_NUM_BITMAPS) ? ACTION_ON : ACTION_OFF;
583 
594  case HOTKEY_ZOOM_DEFAULT:
595  return (gui_->get_zoom_factor() == 1.0) ? ACTION_ON : ACTION_OFF;
596 
597  case HOTKEY_NULL:
598  switch (active_menu_) {
599  case editor::MAP:
600  return index == context_manager_->current_context_index()
602  case editor::LOAD_MRU:
603  return ACTION_STATELESS;
604  case editor::PALETTE:
605  return ACTION_STATELESS;
606  case editor::AREA:
609  case editor::ADDON:
610  return ACTION_STATELESS;
611  case editor::SIDE:
612  return static_cast<std::size_t>(index) == gui_->playing_team()
614  case editor::TIME:
617  case editor::LOCAL_TIME:
619  get_current_map_context().get_active_area())
621  case editor::MUSIC:
623  ? ACTION_ON : ACTION_OFF;
624  case editor::SCHEDULE:
625  {
626  tods_map::const_iterator it = tods_.begin();
627  std::advance(it, index);
628  const std::vector<time_of_day>& times1 = it->second.second;
629  const std::vector<time_of_day>& times2 = get_current_map_context().get_time_manager()->times();
630  return (times1 == times2) ? ACTION_SELECTED : ACTION_DESELECTED;
631  }
633  {
634  tods_map::const_iterator it = tods_.begin();
635  std::advance(it, index);
636  const std::vector<time_of_day>& times1 = it->second.second;
637  int active_area = get_current_map_context().get_active_area();
638  const std::vector<time_of_day>& times2 = get_current_map_context().get_time_manager()->times(active_area);
639  return (times1 == times2) ? ACTION_SELECTED : ACTION_DESELECTED;
640  }
641  case editor::UNIT_FACING:
642  {
644  assert(un != get_current_map_context().units().end());
645  return un->facing() == index ? ACTION_SELECTED : ACTION_DESELECTED;
646  }
647  }
648  return ACTION_ON;
649  default:
650  return command_executor::get_action_state(cmd);
651  }
652 }
653 
654 bool editor_controller::do_execute_command(const hotkey::ui_command& cmd, bool press, bool release)
655 {
656  using namespace hotkey;
657  HOTKEY_COMMAND command = cmd.hotkey_command;
658  SCOPE_ED;
659  int index = cmd.index;
660 
661  // nothing here handles release; fall through to base implementation
662  if (!press) {
663  return command_executor::do_execute_command(cmd, press, release);
664  }
665 
666  switch (command) {
667  case HOTKEY_NULL:
668  switch (active_menu_) {
669  case MAP:
670  if (index >= 0) {
671  unsigned i = static_cast<unsigned>(index);
672  if (i < context_manager_->size()) {
673  context_manager_->switch_context(index);
674  toolkit_->hotkey_set_mouse_action(HOTKEY_EDITOR_TOOL_PAINT);
675  return true;
676  }
677  }
678  return false;
679  case LOAD_MRU:
680  if (index >= 0) {
681  context_manager_->load_mru_item(static_cast<unsigned>(index));
682  }
683  return true;
684  case PALETTE:
685  toolkit_->get_palette_manager()->set_group(index);
686  return true;
687  case SIDE:
688  gui_->set_team(index, true);
689  gui_->set_playing_team(index);
690  toolkit_->get_palette_manager()->draw_contents();
691  return true;
692  case AREA:
693  {
695  const std::set<map_location>& area =
697  std::vector<map_location> locs(area.begin(), area.end());
699  gui_->scroll_to_tiles(locs.begin(), locs.end());
700  return true;
701  }
702  case ADDON:
703  return true;
704  case TIME:
705  {
707  gui_->update_tod();
708  return true;
709  }
710  case LOCAL_TIME:
711  {
713  return true;
714  }
715  case MUSIC:
716  {
717  //TODO mark the map as changed
720  std::vector<config> items;
721  items.emplace_back("id", "editor-playlist");
722  std::shared_ptr<gui::button> b = gui_->find_menu_button("menu-playlist");
723  show_menu(items, b->location().x +1, b->location().y + b->height() +1, false, *gui_);
724  return true;
725  }
726  case SCHEDULE:
727  {
728  tods_map::iterator iter = tods_.begin();
729  std::advance(iter, index);
730  get_current_map_context().replace_schedule(iter->second.second);
731  // TODO: test again after the assign-schedule menu is fixed. Should work, though.
732  gui_->update_tod();
733  return true;
734  }
735  case LOCAL_SCHEDULE:
736  {
737  tods_map::iterator iter = tods_.begin();
738  std::advance(iter, index);
739  get_current_map_context().replace_local_schedule(iter->second.second);
740  return true;
741  }
742  case UNIT_FACING:
743  {
745  assert(un != get_current_map_context().units().end());
746  un->set_facing(map_location::DIRECTION(index));
747  un->anim_comp().set_standing();
748  return true;
749  }
750  }
751  return true;
752 
753  //Zoom
754  case HOTKEY_ZOOM_IN:
755  gui_->set_zoom(true);
757  toolkit_->set_mouseover_overlay(*gui_);
758  return true;
759  case HOTKEY_ZOOM_OUT:
760  gui_->set_zoom(false);
762  toolkit_->set_mouseover_overlay(*gui_);
763  return true;
764  case HOTKEY_ZOOM_DEFAULT:
765  gui_->toggle_default_zoom();
767  toolkit_->set_mouseover_overlay(*gui_);
768  return true;
769 
770  //Palette
772  //TODO this code waits for the gui2 dialog to get ready
773  // std::vector< std::pair< std::string, std::string >> blah_items;
774  // toolkit_->get_palette_manager()->active_palette().expand_palette_groups_menu(blah_items);
775  // int selected = 1; //toolkit_->get_palette_manager()->active_palette().get_selected;
776  // gui2::teditor_select_palette_group::execute(selected, blah_items);
777  return true;
779  toolkit_->get_palette_manager()->scroll_up();
780  return true;
782  toolkit_->get_palette_manager()->scroll_down();
783  return true;
784 
785  case HOTKEY_QUIT_GAME:
787  do_quit_ = true;
789  }
790  return true;
793  return true;
795  context_manager_->save_all_maps(true);
796  do_quit_ = true;
798  return true;
801  return true;
803  toolkit_->get_palette_manager()->active_palette().swap();
804  return true;
806  if (dynamic_cast<const editor_action_chain*>(get_current_map_context().last_undo_action()) != nullptr) {
808  context_manager_->refresh_after_action();
809  } else {
810  undo();
811  }
812  return true;
813 
814  //Tool Selection
823  toolkit_->hotkey_set_mouse_action(command);
824  return true;
825 
826  case HOTKEY_EDITOR_PBL:
827  if(current_addon_id_ == "") {
829  context_manager_->set_addon_id(current_addon_id_);
830  }
831 
832  if(current_addon_id_ != "") {
833  context_manager_->edit_pbl();
834  }
835  return true;
836 
838  if(current_addon_id_ == "") {
840  context_manager_->set_addon_id(current_addon_id_);
841  }
842 
843  if(current_addon_id_ != "") {
844  context_manager_->change_addon_id();
845  }
846  return true;
847 
849  add_area();
850  return true;
851 
853  change_unit_id();
854  return true;
855 
856  return true;
858  {
859  map_location loc = gui_->mouseover_hex();
861  bool unrenamable = un->unrenamable();
862  un->set_unrenamable(!unrenamable);
863  }
864  return true;
866  {
867  map_location loc = gui_->mouseover_hex();
869  bool canrecruit = un->can_recruit();
870  un->set_can_recruit(!canrecruit);
871  un->anim_comp().set_standing();
872  }
873  return true;
874  case HOTKEY_DELETE_UNIT:
875  {
876  map_location loc = gui_->mouseover_hex();
877  perform_delete(std::make_unique<editor_action_unit_delete>(loc));
878  }
879  return true;
880  case HOTKEY_EDITOR_CLIPBOARD_PASTE: //paste is somewhat different as it might be "one action then revert to previous mode"
881  toolkit_->hotkey_set_mouse_action(command);
882  return true;
883 
884  //Clipboard
886  context_manager_->get_clipboard().rotate_60_cw();
887  toolkit_->update_mouse_action_highlights();
888  return true;
890  context_manager_->get_clipboard().rotate_60_ccw();
891  toolkit_->update_mouse_action_highlights();
892  return true;
894  context_manager_->get_clipboard().flip_horizontal();
895  toolkit_->update_mouse_action_highlights();
896  return true;
898  context_manager_->get_clipboard().flip_vertical();
899  toolkit_->update_mouse_action_highlights();
900  return true;
901 
902  //Brushes
904  toolkit_->cycle_brush();
905  return true;
907  toolkit_->set_brush("brush-1");
908  return true;
910  toolkit_->set_brush("brush-2");
911  return true;
913  toolkit_->set_brush("brush-3");
914  return true;
916  toolkit_->set_brush("brush-nw-se");
917  return true;
919  toolkit_->set_brush("brush-sw-ne");
920  return true;
921 
923  copy_selection();
924  return true;
926  cut_selection();
927  return true;
929  context_manager_->rename_area_dialog();
930  return true;
932  save_area();
933  return true;
936  return true;
938  if(!get_current_map_context().map().everything_selected()) {
939  context_manager_->perform_refresh(editor_action_select_all());
940  return true;
941  }
942  [[fallthrough]];
945  return true;
947  context_manager_->perform_refresh(editor_action_select_none());
948  return true;
950  context_manager_->fill_selection();
951  return true;
954  get_current_map_context().map().selection()));
955  return true;
956 
958  context_manager_->edit_scenario_dialog();
959  return true;
960 
963  get_current_map_context().get_active_area());
964  return true;
965 
966  // map specific
968  context_manager_->close_current_context();
969  // Copy behaviour from when switching windows to always reset the active tool to the Paint Tool
970  // This avoids the situation of having a scenario-specific tool active in a map context which can cause a crash if used
971  // Not elegant but at least avoids a potential crash and is consistent with existing behaviour
972  toolkit_->hotkey_set_mouse_action(HOTKEY_EDITOR_TOOL_PAINT);
973  return true;
975  context_manager_->load_map_dialog();
976  return true;
978  context_manager_->revert_map();
979  return true;
981  context_manager_->new_map_dialog();
982  return true;
984  if(current_addon_id_ == "") {
986  context_manager_->set_addon_id(current_addon_id_);
987  }
988 
989  if(current_addon_id_ != "") {
990  context_manager_->new_scenario_dialog();
991  }
992  return true;
994  save_map();
995  return true;
997  context_manager_->save_all_maps();
998  return true;
1000  context_manager_->save_map_as_dialog();
1001  return true;
1003  if(current_addon_id_ == "") {
1005  context_manager_->set_addon_id(current_addon_id_);
1006  }
1007 
1008  if(current_addon_id_ != "") {
1009  context_manager_->save_scenario_as_dialog();
1010  }
1011  return true;
1013  context_manager_->generate_map_dialog();
1014  return true;
1016  context_manager_->apply_mask_dialog();
1017  return true;
1019  context_manager_->create_mask_to_dialog();
1020  return true;
1022  context_manager_->resize_map_dialog();
1023  return true;
1024 
1025  // Side specific ones
1027  if(get_current_map_context().teams().size() >= 9) {
1028  size_t new_side_num = get_current_map_context().teams().size() + 1;
1029  toolkit_->get_palette_manager()->location_palette_->add_item(std::to_string(new_side_num));
1030  }
1032  gui_->init_flags();
1033  return true;
1035  gui_->set_team(0, true);
1036  gui_->set_playing_team(0);
1038  return true;
1040  context_manager_->edit_side_dialog(gui_->viewing_team());
1041  return true;
1042 
1043  // Transitions
1045  context_manager_->set_update_transitions_mode(2);
1046  return true;
1048  context_manager_->set_update_transitions_mode(1);
1049  return true;
1051  context_manager_->set_update_transitions_mode(0);
1052  return true;
1054  if(context_manager_->toggle_update_transitions()) {
1055  return true;
1056  }
1057  [[fallthrough]];
1059  context_manager_->refresh_all();
1060  return true;
1061  // Refresh
1062  case HOTKEY_EDITOR_REFRESH:
1063  context_manager_->reload_map();
1064  return true;
1067  return true;
1068 
1072  gui().invalidate_all();
1073  return true;
1077  gui().invalidate_all();
1078  return true;
1082  gui().invalidate_all();
1083  return true;
1085  location_palette* lp = dynamic_cast<location_palette*>(&toolkit_->get_palette_manager()->active_palette());
1086  if (lp) {
1087  perform_delete(std::make_unique<editor_action_starting_position>(map_location(), lp->selected_item()));
1088  // No idea if this is the right thing to call, but it ensures starting
1089  // position labels get removed on delete.
1090  context_manager_->refresh_after_action();
1091  }
1092  return true;
1093  }
1094  default:
1095  return hotkey::command_executor::do_execute_command(cmd, press, release);
1096  }
1097 }
1098 
1100 {
1101  help::show_help("..editor");
1102 }
1103 
1104 void editor_controller::show_menu(const std::vector<config>& items_arg, int xloc, int yloc, bool context_menu, display& disp)
1105 {
1106  if(context_menu) {
1107  if(!get_current_map_context().map().on_board_with_border(gui().hex_clicked_on(xloc, yloc))) {
1108  return;
1109  }
1110  }
1111 
1112  std::vector<config> items;
1113  for(const auto& c : items_arg) {
1114  const std::string& id = c["id"];
1115 
1117 
1118  if((can_execute_command(cmd) && (!context_menu || in_context_menu(cmd)))
1120  {
1121  items.emplace_back("id", id);
1122  }
1123  }
1124 
1125  // No point in showing an empty menu.
1126  if(items.empty()) {
1127  return;
1128  }
1129 
1130  // Based on the ID of the first entry, we fill the menu contextually.
1131  const std::string& first_id = items.front()["id"];
1132 
1133  if(first_id == "EDITOR-LOAD-MRU-PLACEHOLDER") {
1135  context_manager_->expand_load_mru_menu(items, 0);
1136  }
1137 
1138  if(first_id == "editor-switch-map") {
1140  context_manager_->expand_open_maps_menu(items, 0);
1141  }
1142 
1143  if(first_id == "editor-palette-groups") {
1145  toolkit_->get_palette_manager()->active_palette().expand_palette_groups_menu(items, 0);
1146  }
1147 
1148  if(first_id == "editor-switch-side") {
1150  context_manager_->expand_sides_menu(items, 0);
1151  }
1152 
1153  if(first_id == "editor-switch-area") {
1155  context_manager_->expand_areas_menu(items, 0);
1156  }
1157 
1158  if(first_id == "editor-pbl") {
1160  }
1161 
1162  if(!items.empty() && items.front()["id"] == "editor-switch-time") {
1164  context_manager_->expand_time_menu(items, 0);
1165  }
1166 
1167  if(first_id == "editor-assign-local-time") {
1169  context_manager_->expand_local_time_menu(items, 0);
1170  }
1171 
1172  if(first_id == "menu-unit-facings") {
1174  auto pos = items.erase(items.begin());
1175  int dir = 0;
1176  std::generate_n(std::inserter<std::vector<config>>(items, pos), static_cast<int>(map_location::NDIRECTIONS), [&dir]() -> config {
1178  });
1179  }
1180 
1181  if(first_id == "editor-playlist") {
1183  auto pos = items.erase(items.begin());
1184  std::transform(music_tracks_.begin(), music_tracks_.end(), std::inserter<std::vector<config>>(items, pos), [](const sound::music_track& track) -> config {
1185  return config {"label", track.title().empty() ? track.id() : track.title()};
1186  });
1187  }
1188 
1189  if(first_id == "editor-assign-schedule") {
1191  auto pos = items.erase(items.begin());
1192  std::transform(tods_.begin(), tods_.end(), std::inserter<std::vector<config>>(items, pos), [](const tods_map::value_type& tod) -> config {
1193  return config {"label", tod.second.first};
1194  });
1195  }
1196 
1197  if(first_id == "editor-assign-local-schedule") {
1199  auto pos = items.erase(items.begin());
1200  std::transform(tods_.begin(), tods_.end(), std::inserter<std::vector<config>>(items, pos), [](const tods_map::value_type& tod) -> config {
1201  return config {"label", tod.second.first};
1202  });
1203  }
1204 
1205  command_executor::show_menu(items, xloc, yloc, context_menu, disp);
1206 }
1207 
1209 {
1210  gui_->clear_help_string();
1211  gui2::dialogs::preferences_dialog::display();
1212 
1213  gui_->queue_rerender();
1214 }
1215 
1217 {
1219  gui_->invalidate_all();
1220 }
1221 
1223 {
1224  map_location loc = gui_->mouseover_hex();
1225  const unit_map & units = get_current_map_context().units();
1226  const unit_map::const_unit_iterator un = units.find(loc);
1227  if(un != units.end()) {
1228  help::show_unit_help(un->type_id(), un->type().show_variations_in_help(), false);
1229  } else {
1230  help::show_help("..units");
1231  }
1232 }
1233 
1234 
1236 {
1237  if (!get_current_map_context().map().selection().empty()) {
1238  context_manager_->get_clipboard() = map_fragment(get_current_map_context().map(), get_current_map_context().map().selection());
1239  context_manager_->get_clipboard().center_by_mass();
1240  }
1241 }
1242 
1244 {
1245  map_location loc = gui_->mouseover_hex();
1246  unit_map& units = get_current_map_context().units();
1247  const unit_map::unit_iterator& un = units.find(loc);
1248 
1249  const std::string title(N_("Change Unit ID"));
1250  const std::string label(N_("ID:"));
1251 
1252  if(un != units.end()) {
1253  std::string id = un->id();
1254  if (gui2::dialogs::edit_text::execute(title, label, id)) {
1255  un->set_id(id);
1256  }
1257  }
1258 }
1259 
1261 {
1262  map_location loc = gui_->mouseover_hex();
1263  unit_map& units = get_current_map_context().units();
1264  const unit_map::unit_iterator& un = units.find(loc);
1265 
1266  const std::string title(N_("Rename Unit"));
1267  const std::string label(N_("Name:"));
1268 
1269  if(un != units.end()) {
1270  std::string name = un->name();
1271  if(gui2::dialogs::edit_text::execute(title, label, name)) {
1272  //TODO we may not want a translated name here.
1273  un->set_name(name);
1274  }
1275  }
1276 }
1277 
1279 {
1281 }
1282 
1284 {
1285  copy_selection();
1287 }
1288 
1290 {
1291  const std::set<map_location>& area = get_current_map_context().map().selection();
1293 }
1294 
1296 {
1297  const std::set<map_location>& area = get_current_map_context().map().selection();
1299 }
1300 
1302 {
1303  std::stringstream ssx, ssy;
1304  std::set<map_location>::const_iterator i = get_current_map_context().map().selection().begin();
1305  if (i != get_current_map_context().map().selection().end()) {
1306  ssx << "x = " << i->wml_x();
1307  ssy << "y = " << i->wml_y();
1308  ++i;
1309  while (i != get_current_map_context().map().selection().end()) {
1310  ssx << ", " << i->wml_x();
1311  ssy << ", " << i->wml_y();
1312  ++i;
1313  }
1314  ssx << "\n" << ssy.str() << "\n";
1315  desktop::clipboard::copy_to_clipboard(ssx.str(), false);
1316  }
1317 }
1318 
1319 void editor_controller::perform_delete(std::unique_ptr<editor_action> action)
1320 {
1321  if (action) {
1323  }
1324 }
1325 
1326 void editor_controller::perform_refresh_delete(std::unique_ptr<editor_action> action, bool drag_part /* =false */)
1327 {
1328  if (action) {
1329  context_manager_->perform_refresh(*action, drag_part);
1330  }
1331 }
1332 
1334 {
1336  context_manager_->refresh_all();
1337 }
1338 
1340 {
1341  set_button_state();
1342  toolkit_->adjust_size();
1344 }
1345 
1347 {
1349  context_manager_->refresh_after_action();
1350 }
1351 
1353 {
1355  context_manager_->refresh_after_action();
1356 }
1357 
1358 void editor_controller::mouse_motion(int x, int y, const bool /*browse*/,
1359  bool update, map_location /*new_loc*/)
1360 {
1361  if (mouse_handler_base::mouse_motion_default(x, y, update)) return;
1362  map_location hex_clicked = gui().hex_clicked_on(x, y);
1363  if (get_current_map_context().map().on_board_with_border(drag_from_hex_) && is_dragging()) {
1364  std::unique_ptr<editor_action> a;
1365  bool partial = false;
1366  // last_undo is a non-owning pointer. Although it could have other uses, it seems to be
1367  // mainly (only?) used for printing debugging information.
1368  auto last_undo = get_current_map_context().last_undo_action();
1369  if (dragging_left_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(1)) != 0) {
1370  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
1371  a = get_mouse_action().drag_left(*gui_, x, y, partial, last_undo);
1372  } else if (dragging_right_ && (sdl::get_mouse_button_mask() & SDL_BUTTON(3)) != 0) {
1373  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return;
1374  a = get_mouse_action().drag_right(*gui_, x, y, partial, last_undo);
1375  }
1376  //Partial means that the mouse action has modified the
1377  //last undo action and the controller shouldn't add
1378  //anything to the undo stack (hence a different perform_ call)
1379  if (a != nullptr) {
1380  if (partial) {
1382  } else {
1384  }
1385  context_manager_->refresh_after_action(true);
1386  }
1387  } else {
1388  get_mouse_action().move(*gui_, hex_clicked);
1389  }
1390  gui().highlight_hex(hex_clicked);
1391 }
1392 
1393 void editor_controller::touch_motion(int /* x */, int /* y */, const bool /* browse */, bool /* update */, map_location /* new_loc */)
1394 {
1395  // Not implemented at all. Sorry, it's a very low priority for iOS port.
1396 }
1397 
1399 {
1400  return get_current_map_context().map().on_board_with_border(gui().hex_clicked_on(x,y));
1401 }
1402 
1403 bool editor_controller::right_click_show_menu(int /*x*/, int /*y*/, const bool /*browse*/)
1404 {
1406 }
1407 
1408 bool editor_controller::left_click(int x, int y, const bool browse)
1409 {
1410  toolkit_->clear_mouseover_overlay();
1411  if (mouse_handler_base::left_click(x, y, browse))
1412  return true;
1413 
1414  LOG_ED << "Left click, after generic handling";
1415  map_location hex_clicked = gui().hex_clicked_on(x, y);
1416  if (!get_current_map_context().map().on_board_with_border(hex_clicked))
1417  return true;
1418 
1419  LOG_ED << "Left click action " << hex_clicked;
1420  auto a = get_mouse_action().click_left(*gui_, x, y);
1421  if(a) {
1422  perform_refresh_delete(std::move(a), true);
1423  set_button_state();
1424  }
1425 
1426  return false;
1427 }
1428 
1429 void editor_controller::left_drag_end(int x, int y, const bool /*browse*/)
1430 {
1431  auto a = get_mouse_action().drag_end_left(*gui_, x, y);
1432  perform_delete(std::move(a));
1433 }
1434 
1435 void editor_controller::left_mouse_up(int x, int y, const bool /*browse*/)
1436 {
1437  auto a = get_mouse_action().up_left(*gui_, x, y);
1438  if(a) {
1439  perform_delete(std::move(a));
1440  set_button_state();
1441  }
1442  toolkit_->set_mouseover_overlay();
1443  context_manager_->refresh_after_action();
1444 }
1445 
1446 bool editor_controller::right_click(int x, int y, const bool browse)
1447 {
1448  toolkit_->clear_mouseover_overlay();
1449  if (mouse_handler_base::right_click(x, y, browse)) return true;
1450  LOG_ED << "Right click, after generic handling";
1451  map_location hex_clicked = gui().hex_clicked_on(x, y);
1452  if (!get_current_map_context().map().on_board_with_border(hex_clicked)) return true;
1453  LOG_ED << "Right click action " << hex_clicked;
1454  auto a = get_mouse_action().click_right(*gui_, x, y);
1455  if(a) {
1456  perform_refresh_delete(std::move(a), true);
1457  set_button_state();
1458  }
1459  return false;
1460 }
1461 
1462 void editor_controller::right_drag_end(int x, int y, const bool /*browse*/)
1463 {
1464  auto a = get_mouse_action().drag_end_right(*gui_, x, y);
1465  perform_delete(std::move(a));
1466 }
1467 
1468 void editor_controller::right_mouse_up(int x, int y, const bool browse)
1469 {
1470  // Call base method to handle context menus.
1471  mouse_handler_base::right_mouse_up(x, y, browse);
1472 
1473  auto a = get_mouse_action().up_right(*gui_, x, y);
1474  if(a) {
1475  perform_delete(std::move(a));
1476  set_button_state();
1477  }
1478  toolkit_->set_mouseover_overlay();
1479  context_manager_->refresh_after_action();
1480 }
1481 
1483 {
1484  const map_location& loc = gui().mouseover_hex();
1485  if (get_current_map_context().map().on_board(loc) == false)
1486  return;
1487 
1490 }
1491 
1492 void editor_controller::process_keyup_event(const SDL_Event& event)
1493 {
1494  auto a = get_mouse_action().key_event(gui(), event);
1495  perform_refresh_delete(std::move(a));
1496  toolkit_->set_mouseover_overlay();
1497 }
1498 
1500  return this;
1501 }
1502 
1504 {
1506 }
1507 
1509 {
1511 }
1512 
1514 {
1516 }
1517 
1519 {
1521 }
1522 
1524 {
1525  return toolkit_->get_palette_manager()->active_palette().action_pressed();
1526 }
1527 
1528 } //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:81
void toggle_debug_flag(DEBUG_FLAG flag)
Definition: display.hpp:990
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:1554
@ DEBUG_COORDINATES
Overlays x,y coords on tiles.
Definition: display.hpp:962
@ DEBUG_NUM_BITMAPS
Overlays number of bitmaps on tiles.
Definition: display.hpp:968
@ DEBUG_TERRAIN_CODES
Overlays terrain codes on tiles.
Definition: display.hpp:965
void invalidate_all()
Function to invalidate all tiles.
Definition: display.cpp:3130
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:2320
void set_debug_flag(DEBUG_FLAG flag, bool value)
Definition: display.hpp:985
const map_location & mouseover_hex() const
Definition: display.hpp:301
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".
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
This shows the dialog to modify tod schedules.
Definition: custom_tod.hpp:49
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
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
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:209
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:60
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_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:923
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
void set_draw_num_of_bitmaps(bool value)
Definition: editor.cpp:57
bool draw_terrain_codes()
Definition: editor.cpp:37
bool draw_hex_coordinates()
Definition: editor.cpp:45
bool draw_num_of_bitmaps()
Definition: editor.cpp:53
void set_draw_hex_coordinates(bool value)
Definition: editor.cpp:49
void set_draw_terrain_codes(bool value)
Definition: editor.cpp:41
bool minimap_movement_coding()
Definition: general.cpp:827
bool minimap_draw_villages()
Definition: general.cpp:857
void set_grid(bool ison)
Definition: general.cpp:570
bool minimap_terrain_coding()
Definition: general.cpp:837
bool minimap_draw_terrain()
Definition: general.cpp:867
bool minimap_draw_units()
Definition: general.cpp:847
bool grid()
Definition: general.cpp:565
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