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 
21 #include "game_events/handlers.hpp"
23 #include "play_controller.hpp"
24 #include "resources.hpp"
25 
26 #include "config.hpp"
27 #include "game_data.hpp"
28 #include "log.hpp"
29 #include "map/location.hpp"
30 
31 static lg::log_domain log_engine("engine");
32 #define WRN_NG LOG_STREAM(warn, log_engine)
33 #define LOG_NG LOG_STREAM(info, log_engine)
34 
35 // This file is in the game_events namespace.
36 namespace game_events
37 {
39  : wml_menu_items_()
40 {
41 }
42 
43 /**
44  * Destructor.
45  * Default implementation, but defined here because this function needs to be
46  * able to see wml_menu_item's destructor.
47  */
49 {
50 }
51 
52 /** Erases the item with id @a key. */
54 {
55  // Locate the item to erase.
56  const auto iter = wml_menu_items_.find(id);
57 
58  if(iter == wml_menu_items_.end()) {
59  WRN_NG << "Trying to remove non-existent menu item '" << id << "'; ignoring." << std::endl;
60  // No such item.
61  return false;
62  }
63 
64  // Clean up our bookkeeping.
65  iter->second->finish_handler();
66 
67  // Remove the item from the map.
68  wml_menu_items_.erase(iter);
69 
70  return true; // Erased one item.
71 }
72 
73 /**
74  * Fires the menu item with the given @a id.
75  * @returns true if a matching item was found (even if it could not be fired).
76  * NOTE: The return value could be altered if it is decided that
77  * play_controller::execute_command() needs something different.
78  */
80  const std::string& id, const map_location& hex, game_data& gamedata, filter_context& fc, unit_map& units) const
81 {
82  // Does this item exist?
83  item_ptr wmi = get_item(id);
84  if(!wmi) {
85  return false;
86  }
87 
88  // Prepare for can show().
89  gamedata.get_variable("x1") = hex.wml_x();
90  gamedata.get_variable("y1") = hex.wml_y();
91  scoped_xy_unit highlighted_unit("unit", hex, units);
92 
93  // Can this item be shown?
94  if(wmi->can_show(hex, gamedata, fc)) {
95  wmi->fire_event(hex, gamedata);
96  }
97  return true;
98 }
99 
100 /**
101  * Returns the menu items that can be shown for the given location.
102  *
103  * @param[out] items Pointers to applicable menu items will be pushed onto @a items.
104  * @param[out] descriptions Menu item text will be pushed onto @a descriptions (in the same order as @a items).
105  */
107  std::vector<std::shared_ptr<const wml_menu_item>>& items,
108  std::vector<config>& descriptions,
109  filter_context& fc,
111  unit_map& units) const
112 {
113  if(empty()) {
114  // Nothing to do (skip setting game variables).
115  return;
116  }
117 
118  // Prepare for can show().
119  gamedata.get_variable("x1") = hex.wml_x();
120  gamedata.get_variable("y1") = hex.wml_y();
121  scoped_xy_unit highlighted_unit("unit", hex, units);
122 
123  // Check each menu item.
124  for(const auto& item_pair : wml_menu_items_) {
125  item_ptr item = item_pair.second;
126 
127  // Can this item be shown?
128  if(item->use_wml_menu() && (!item->is_synced() || resources::controller->can_use_synced_wml_menu())
129  && item->can_show(hex, gamedata, fc)) {
130  // Include this item.
131  items.push_back(item);
132  descriptions.emplace_back(config {"id", item->menu_text()});
133  }
134  }
135 }
136 
138 {
139  auto iter = wml_menu_items_.find(id);
140  if(iter != wml_menu_items_.end()) {
141  return iter->second;
142  }
143 
144  return nullptr;
145 }
146 
147 /**
148  * Initializes the implicit event handlers for inlined [command]s.
149  */
151 {
152  // Applying default hotkeys here currently does not work because
153  // the hotkeys are reset by play_controler::init_managers() ->
154  // display_manager::display_manager, which is called after this.
155  // The result is that default wml hotkeys will be ignored if wml
156  // hotkeys are set to default in the preferences menu. (They are
157  // still reapplied if set_menu_item is called again, for example
158  // by starting a new campaign.) Since it isn't that important
159  // I'll just leave it for now.
160 
161  unsigned wmi_count = 0;
162 
163  // Loop through each menu item.
164  for(const auto& item : wml_menu_items_) {
165  // If this menu item has a [command], add a handler for it.
166  item.second->init_handler();
167 
168  // Count the menu items (for the diagnostic message).
169  ++wmi_count;
170  }
171 
172  // Diagnostic:
173  if(wmi_count > 0) {
174  LOG_NG << wmi_count << " WML menu items found, loaded." << std::endl;
175  }
176 }
177 
179 {
180  // Loop through our items.
181  for(const auto& item : wml_menu_items_) {
182  // Add this item as a child of cfg.
183  item.second->to_config(cfg.add_child("menu_item"));
184  }
185 }
186 
187 /**
188  * Updates or creates (as appropriate) the menu item with the given @a id.
189  */
190 void wmi_manager::set_item(const std::string& id, const vconfig& menu_item)
191 {
192  auto iter = wml_menu_items_.begin();
193  bool success;
194 
195  // First, try to insert a brand new menu item.
196  std::tie(iter, success) = wml_menu_items_.emplace(id, item_ptr(new wml_menu_item(id, menu_item)));
197 
198  // If an entry already exists, reset it.
199  if(!success) {
200  // Create a new menu item based on the old. This leaves the old item
201  // alone in case someone else is holding on to (and processing) it.
202  iter->second.reset(new wml_menu_item(id, menu_item, *iter->second));
203  }
204 }
205 
206 /**
207  * Sets the current menu items to the "menu_item" children of @a cfg.
208  */
210 {
211  wml_menu_items_.clear();
212  for(const config& item : cfg.child_range("menu_item")) {
213  if(!item.has_attribute("id")) {
214  continue;
215  }
216 
217  const std::string& id = item["id"];
218  bool success;
219 
220  std::tie(std::ignore, success) = wml_menu_items_.emplace(id, item_ptr(new wml_menu_item(id, item)));
221 
222  if(!success) {
223  WRN_NG << "duplicate menu item (" << id << ") while loading from config" << std::endl;
224  }
225  }
226 }
227 
228 } // 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:79
#define WRN_NG
Definition: wmi_manager.cpp:32
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:295
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:53
std::shared_ptr< wml_menu_item > item_ptr
wml_menu_item pointers
Definition: wmi_manager.hpp:42
#define LOG_NG
Definition: wmi_manager.cpp:33
Declarations for a container for wml_menu_item.
~wmi_manager()
Destructor.
Definition: wmi_manager.cpp:48
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:408
Define the handlers for the game's events mechanism.
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")