The Battle for Wesnoth  1.13.10+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
wmi_manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2017 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project http://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. */
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) const
80 {
81  // Does this item exist?
82  item_ptr wmi = get_item(id);
83  if(!wmi) {
84  return false;
85  }
86 
87  // Prepare for can show().
88  gamedata.get_variable("x1") = hex.wml_x();
89  gamedata.get_variable("y1") = hex.wml_y();
90  scoped_xy_unit highlighted_unit("unit", hex, units);
91 
92  // Can this item be shown?
93  if(wmi->can_show(hex, gamedata, fc)) {
94  wmi->fire_event(hex, gamedata);
95  }
96  return true;
97 }
98 
99 /**
100  * Returns the menu items that can be shown for the given location.
101  *
102  * @param[out] items Pointers to applicable menu items will be pushed onto @a items.
103  * @param[out] descriptions Menu item text will be pushed onto @a descriptions (in the same order as @a items).
104  */
106  std::vector<std::shared_ptr<const wml_menu_item>>& items,
107  std::vector<config>& descriptions,
108  filter_context& fc,
110  unit_map& units) const
111 {
112  if(empty()) {
113  // Nothing to do (skip setting game variables).
114  return;
115  }
116 
117  // Prepare for can show().
118  gamedata.get_variable("x1") = hex.wml_x();
119  gamedata.get_variable("y1") = hex.wml_y();
120  scoped_xy_unit highlighted_unit("unit", hex, units);
121 
122  // Check each menu item.
123  for(const auto& item_pair : wml_menu_items_) {
124  item_ptr item = item_pair.second;
125 
126  // Can this item be shown?
127  if(item->use_wml_menu() && (!item->is_synced() || resources::controller->can_use_synced_wml_menu())
128  && item->can_show(hex, gamedata, fc)) {
129  // Include this item.
130  items.push_back(item);
131  descriptions.emplace_back(config {"id", item->menu_text()});
132  }
133  }
134 }
135 
137 {
138  auto iter = wml_menu_items_.find(id);
139  if(iter != wml_menu_items_.end()) {
140  return iter->second;
141  }
142 
143  return nullptr;
144 }
145 
146 /**
147  * Initializes the implicit event handlers for inlined [command]s.
148  */
150 {
151  // Applying default hotkeys here currently does not work because
152  // the hotkeys are reset by play_controler::init_managers() ->
153  // display_manager::display_manager, which is called after this.
154  // The result is that default wml hotkeys will be ignored if wml
155  // hotkeys are set to default in the preferences menu. (They are
156  // still reapplied if set_menu_item is called again, for example
157  // by starting a new campaign.) Since it isn't that important
158  // I'll just leave it for now.
159 
160  unsigned wmi_count = 0;
161 
162  // Loop through each menu item.
163  for(const auto& item : wml_menu_items_) {
164  // If this menu item has a [command], add a handler for it.
165  item.second->init_handler();
166 
167  // Count the menu items (for the diagnostic message).
168  ++wmi_count;
169  }
170 
171  // Diagnostic:
172  if(wmi_count > 0) {
173  LOG_NG << wmi_count << " WML menu items found, loaded." << std::endl;
174  }
175 }
176 
178 {
179  // Loop through our items.
180  for(const auto& item : wml_menu_items_) {
181  // Add this item as a child of cfg.
182  item.second->to_config(cfg.add_child("menu_item"));
183  }
184 }
185 
186 /**
187  * Updates or creates (as appropriate) the menu item with the given @a id.
188  */
189 void wmi_manager::set_item(const std::string& id, const vconfig& menu_item)
190 {
191  auto iter = wml_menu_items_.begin();
192  bool success;
193 
194  // First, try to insert a brand new menu item.
195  std::tie(iter, success) = wml_menu_items_.emplace(id, item_ptr(new wml_menu_item(id, menu_item)));
196 
197  // If an entry already exists, reset it.
198  if(!success) {
199  // Create a new menu item based on the old. This leaves the old item
200  // alone in case someone else is holding on to (and processing) it.
201  iter->second.reset(new wml_menu_item(id, menu_item, *iter->second));
202  }
203 }
204 
205 /**
206  * Sets the current menu items to the "menu_item" children of @a cfg.
207  */
209 {
210  wml_menu_items_.clear();
211  for(const config& item : cfg.child_range("menu_item")) {
212  if(!item.has_attribute("id")) {
213  continue;
214  }
215 
216  const std::string& id = item["id"];
217  bool success;
218 
219  std::tie(std::ignore, success) = wml_menu_items_.emplace(id, item_ptr(new wml_menu_item(id, item)));
220 
221  if(!success) {
222  WRN_NG << "duplicate menu item (" << id << ") while loading from config" << std::endl;
223  }
224  }
225 }
226 
227 } // end namespace game_events
play_controller * controller
Definition: resources.cpp:21
bool empty() const
Returns true if no menu items are being managed.
Definition: wmi_manager.hpp:48
bool fire_item(const std::string &id, const map_location &hex, game_data &gamedata, filter_context &fc, unit_map &units) const
Fires the menu item with the given id.
Definition: wmi_manager.cpp:78
#define WRN_NG
Definition: wmi_manager.cpp:31
std::map< std::string, item_ptr > wml_menu_items_
Definition: wmi_manager.hpp:97
std::vector< char_t > string
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.
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:343
bool can_use_synced_wml_menu() const
int wml_y() const
Definition: location.hpp:116
const std::vector< std::string > items
Definitions for the interface to Wesnoth Markup Language (WML).
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
item_ptr get_item(const std::string &id) const
Gets the menu item with the specified ID.
int wml_x() const
Definition: location.hpp:115
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.
void to_config(config &cfg) const
Encapsulates the map of the game.
Definition: location.hpp:40
Domain specific events.
Definition: action_wml.cpp:88
config & add_child(config_key_type key)
Definition: config.cpp:456
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
void init_handlers() const
Initializes the implicit event handlers for inlined [command]s.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
unit_map * units
Definition: resources.cpp:34
static lg::log_domain log_engine("engine")