The Battle for Wesnoth  1.15.0-dev
wmi_manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 /**
16  * @file
17  * Definitions for a container for wml_menu_item.
18  */
19 
22 #include "play_controller.hpp"
23 #include "resources.hpp"
24 
25 #include "config.hpp"
26 #include "game_data.hpp"
27 #include "log.hpp"
28 #include "map/location.hpp"
29 
30 static lg::log_domain log_engine("engine");
31 #define WRN_NG LOG_STREAM(warn, log_engine)
32 #define LOG_NG LOG_STREAM(info, log_engine)
33 
34 // This file is in the game_events namespace.
35 namespace game_events
36 {
38  : wml_menu_items_()
39 {
40 }
41 
42 /**
43  * Destructor.
44  * Default implementation, but defined here because this function needs to be
45  * able to see wml_menu_item's destructor.
46  */
48 {
49 }
50 
51 /** Erases the item with id @a key. */
52 bool wmi_manager::erase(const std::string& id)
53 {
54  // Locate the item to erase.
55  const auto iter = wml_menu_items_.find(id);
56 
57  if(iter == wml_menu_items_.end()) {
58  WRN_NG << "Trying to remove non-existent menu item '" << id << "'; ignoring." << std::endl;
59  // No such item.
60  return false;
61  }
62 
63  // Clean up our bookkeeping.
64  iter->second->finish_handler();
65 
66  // Remove the item from the map.
67  wml_menu_items_.erase(iter);
68 
69  return true; // Erased one item.
70 }
71 
72 /**
73  * Fires the menu item with the given @a id.
74  * @returns true if a matching item was found (even if it could not be fired).
75  * NOTE: The return value could be altered if it is decided that
76  * play_controller::execute_command() needs something different.
77  */
79  const std::string& id, const map_location& hex, game_data& gamedata, filter_context& fc, unit_map& units, bool is_key_hold_repeat) const
80 {
81  // Does this item exist?
82  item_ptr wmi = get_item(id);
83  if(!wmi) {
84  return false;
85  } else if(is_key_hold_repeat && !wmi->hotkey_repeat()) {
86  return false;
87  }
88 
89  // Prepare for can show().
90  gamedata.get_variable("x1") = hex.wml_x();
91  gamedata.get_variable("y1") = hex.wml_y();
92  scoped_xy_unit highlighted_unit("unit", hex, units);
93 
94  // Can this item be shown?
95  if(wmi->can_show(hex, gamedata, fc)) {
96  wmi->fire_event(hex, gamedata);
97  }
98  return true;
99 }
100 
101 /**
102  * Returns the menu items that can be shown for the given location.
103  *
104  * @param[out] items Pointers to applicable menu items will be pushed onto @a items.
105  * @param[out] descriptions Menu item text will be pushed onto @a descriptions (in the same order as @a items).
106  */
108  std::vector<std::shared_ptr<const wml_menu_item>>& items,
109  std::vector<config>& descriptions,
110  filter_context& fc,
112  unit_map& units) const
113 {
114  if(empty()) {
115  // Nothing to do (skip setting game variables).
116  return;
117  }
118 
119  // Prepare for can show().
120  gamedata.get_variable("x1") = hex.wml_x();
121  gamedata.get_variable("y1") = hex.wml_y();
122  scoped_xy_unit highlighted_unit("unit", hex, units);
123 
124  // Check each menu item.
125  for(const auto& item_pair : wml_menu_items_) {
126  item_ptr item = item_pair.second;
127 
128  // Can this item be shown?
129  if(item->use_wml_menu() && (!item->is_synced() || resources::controller->can_use_synced_wml_menu())
130  && item->can_show(hex, gamedata, fc)) {
131  // Include this item.
132  items.push_back(item);
133  descriptions.emplace_back("id", item->menu_text());
134  }
135  }
136 }
137 
138 wmi_manager::item_ptr wmi_manager::get_item(const std::string& id) const
139 {
140  auto iter = wml_menu_items_.find(id);
141  if(iter != wml_menu_items_.end()) {
142  return iter->second;
143  }
144 
145  return nullptr;
146 }
147 
148 /**
149  * Initializes the implicit event handlers for inlined [command]s.
150  */
152 {
153  // Applying default hotkeys here currently does not work because
154  // the hotkeys are reset by play_controler::init_managers() ->
155  // display_manager::display_manager, which is called after this.
156  // The result is that default wml hotkeys will be ignored if wml
157  // hotkeys are set to default in the preferences menu. (They are
158  // still reapplied if set_menu_item is called again, for example
159  // by starting a new campaign.) Since it isn't that important
160  // I'll just leave it for now.
161 
162  unsigned wmi_count = 0;
163 
164  // Loop through each menu item.
165  for(const auto& item : wml_menu_items_) {
166  // If this menu item has a [command], add a handler for it.
167  item.second->init_handler();
168 
169  // Count the menu items (for the diagnostic message).
170  ++wmi_count;
171  }
172 
173  // Diagnostic:
174  if(wmi_count > 0) {
175  LOG_NG << wmi_count << " WML menu items found, loaded." << std::endl;
176  }
177 }
178 
180 {
181  // Loop through our items.
182  for(const auto& item : wml_menu_items_) {
183  // Add this item as a child of cfg.
184  item.second->to_config(cfg.add_child("menu_item"));
185  }
186 }
187 
188 /**
189  * Updates or creates (as appropriate) the menu item with the given @a id.
190  */
191 void wmi_manager::set_item(const std::string& id, const vconfig& menu_item)
192 {
193  auto iter = wml_menu_items_.begin();
194  bool success;
195 
196  // First, try to insert a brand new menu item.
197  std::tie(iter, success) = wml_menu_items_.emplace(id, std::make_shared<wml_menu_item>(id, menu_item));
198 
199  // If an entry already exists, reset it.
200  if(!success) {
201  // Create a new menu item based on the old. This leaves the old item
202  // alone in case someone else is holding on to (and processing) it.
203  iter->second.reset(new wml_menu_item(id, menu_item, *iter->second));
204  }
205 }
206 
207 /**
208  * Sets the current menu items to the "menu_item" children of @a cfg.
209  */
211 {
212  wml_menu_items_.clear();
213  for(const config& item : cfg.child_range("menu_item")) {
214  if(!item.has_attribute("id")) {
215  continue;
216  }
217 
218  const std::string& id = item["id"];
219  bool success;
220 
221  std::tie(std::ignore, success) = wml_menu_items_.emplace(id, std::make_shared<wml_menu_item>(id, item));
222 
223  if(!success) {
224  WRN_NG << "duplicate menu item (" << id << ") while loading from config" << std::endl;
225  }
226  }
227 }
228 
229 } // end namespace game_events
play_controller * controller
Definition: resources.cpp:21
#define WRN_NG
Definition: wmi_manager.cpp:31
std::map< std::string, item_ptr > wml_menu_items_
Definition: wmi_manager.hpp:98
void set_item(const std::string &id, const vconfig &menu_item)
Updates or creates (as appropriate) the menu item with the given id.
child_itors child_range(config_key_type key)
Definition: config.cpp:366
bool empty() const
Returns true if no menu items are being managed.
Definition: wmi_manager.hpp:48
int wml_x() const
Definition: location.hpp:157
const std::vector< std::string > items
Definitions for the interface to Wesnoth Markup Language (WML).
item_ptr get_item(const std::string &id) const
Gets the menu item with the specified ID.
bool fire_item(const std::string &id, const map_location &hex, game_data &gamedata, filter_context &fc, unit_map &units, bool is_key_hold_repeat=false) const
Fires the menu item with the given id.
Definition: wmi_manager.cpp:78
game_data * gamedata
Definition: resources.cpp:22
config::attribute_value & get_variable(const std::string &varname)
throws invalid_variablename_exception if varname is no valid variable name.
Definition: game_data.cpp:62
void init_handlers() const
Initializes the implicit event handlers for inlined [command]s.
int wml_y() const
Definition: location.hpp:158
bool erase(const std::string &id)
Erases the item with the provided id.
Definition: wmi_manager.cpp:52
std::shared_ptr< wml_menu_item > item_ptr
wml_menu_item pointers
Definition: wmi_manager.hpp:42
#define LOG_NG
Definition: wmi_manager.cpp:32
Declarations for a container for wml_menu_item.
~wmi_manager()
Destructor.
Definition: wmi_manager.cpp:47
void set_menu_items(const config &cfg)
Sets the current menu items to the "menu_item" children of cfg.
Encapsulates the map of the game.
Definition: location.hpp:42
void to_config(config &cfg) const
Domain specific events.
Definition: action_wml.cpp:88
bool can_use_synced_wml_menu() const
config & add_child(config_key_type key)
Definition: config.cpp:479
void get_items(const map_location &hex, std::vector< std::shared_ptr< const wml_menu_item >> &items, std::vector< config > &descriptions, filter_context &fc, game_data &gamedata, unit_map &units) const
Returns the menu items that can be shown for the given location.
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
Standard logging facilities (interface).
Container associating units to locations.
Definition: map.hpp:99
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
static lg::log_domain log_engine("engine")