The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
wmi_container.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2016 by David White <[email protected]>
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 
20 #include "global.hpp"
21 #include "wmi_container.hpp"
22 #include "handlers.hpp"
23 #include "menu_item.hpp"
24 #include "resources.hpp"
25 #include "play_controller.hpp"
26 
27 #include "config.hpp"
28 #include "game_data.hpp"
29 #include "log.hpp"
30 #include "map/location.hpp"
31 
32 static lg::log_domain log_engine("engine");
33 #define WRN_NG LOG_STREAM(warn, log_engine)
34 #define LOG_NG LOG_STREAM(info, log_engine)
35 
36 // This file is in the game_events namespace.
37 namespace game_events
38 {
39 
41  : wml_menu_items_()
42 {}
43 
44 /**
45  * Destructor.
46  * Default implementation, but defined here because this function needs to be
47  * able to see wml_menu_item's destructor.
48  */
50 {
51 }
52 
53 
54 /** Erases the item with id @a key. */
56 {
57  // Locate the item to erase.
58  const map_t::iterator iter = wml_menu_items_.find(id);
59 
60  if ( iter == wml_menu_items_.end() ) {
61  WRN_NG << "Trying to remove non-existent menu item '" << id << "'; ignoring." << std::endl;
62  // No such item.
63  return 0;
64  }
65 
66  // Clean up our bookkeeping.
67  iter->second->finish_handler();
68 
69  // Remove the item from the map.
70  wml_menu_items_.erase(iter);
71 
72  return 1; // Erased one item.
73 }
74 
75 /**
76  * Fires the menu item with the given @a id.
77  * @returns true if a matching item was found (even if it could not be fired).
78  * NOTE: The return value could be altered if it is decided that
79  * play_controller::execute_command() needs something different.
80  */
82 {
83  // Does this item exist?
84  const_iterator iter = find(id);
85  if ( iter == end() ) {
86  return false;
87  }
88  const wml_menu_item & wmi = **iter;
89 
90  // Prepare for can show().
91  gamedata.get_variable("x1") = hex.x + 1;
92  gamedata.get_variable("y1") = hex.y + 1;
93  scoped_xy_unit highlighted_unit("unit", hex.x, hex.y, units);
94 
95  // Can this item be shown?
96  if ( wmi.can_show(hex, gamedata, fc) ) {
97  wmi.fire_event(hex, gamedata);
98  }
99  return true;
100 }
101 
102 /**
103  * Returns the menu items that can be shown for the given location.
104  * Should be used with a wmi_pager to limit the number of items displayed at once.
105  *
106  * @param[out] items Pointers to applicable menu items will be pushed onto @a items.
107  * @param[out] descriptions Menu item text will be pushed onto @a descriptions (in the same order as @a items).
108  */
109 std::vector<std::pair<boost::shared_ptr<const wml_menu_item>, std::string> > wmi_container::get_items(const map_location& hex,
111 {
112  std::vector<std::pair<boost::shared_ptr<const wml_menu_item>, std::string> > ret;
113  if ( empty() ) {
114  // Nothing to do (skip setting game variables).
115  return ret;
116  }
117  // Prepare for can show().
118  gamedata.get_variable("x1") = hex.x + 1;
119  gamedata.get_variable("y1") = hex.y + 1;
120  scoped_xy_unit highlighted_unit("unit", hex.x, hex.y, units);
121 
122  // Check each menu item.
123  for (const item_ptr & item : std::make_pair (start, finish))
124  {
125  // Can this item be shown?
126  if ( item->use_wml_menu() && (!item->is_synced() || resources::controller->can_use_synced_wml_menu()) && item->can_show(hex, gamedata, fc) )
127  {
128  // Include this item.
129  ret.push_back(std::make_pair(item, item->menu_text()));
130  }
131  }
132  return ret;
133 }
134 
135 /**
136  * Initializes the implicit event handlers for inlined [command]s.
137  */
139 {
140  // Applying default hotkeys here currently does not work because
141  // the hotkeys are reset by play_controler::init_managers() ->
142  // display_manager::display_manager, which is called after this.
143  // The result is that default wml hotkeys will be ignored if wml
144  // hotkeys are set to default in the preferences menu. (They are
145  // still reapplied if set_menu_item is called again, for example
146  // by starting a new campaign.) Since it isn't that important
147  // I'll just leave it for now.
148 
149  unsigned wmi_count = 0;
150 
151  // Loop through each menu item.
152  for (const item_ptr & wmi : *this) {
153  // If this menu item has a [command], add a handler for it.
154  wmi->init_handler();
155  // Count the menu items (for the diagnostic message).
156  ++wmi_count;
157  }
158 
159  // Diagnostic:
160  if ( wmi_count > 0 ) {
161  LOG_NG << wmi_count << " WML menu items found, loaded." << std::endl;
162  }
163 }
164 
166 {
167  // Loop through our items.
168  for (const item_ptr & item : *this)
169  {
170  // Add this item as a child of cfg.
171  item->to_config(cfg.add_child("menu_item"));
172  }
173 }
174 
175 /**
176  * Updates or creates (as appropriate) the menu item with the given @a id.
177  */
178 void wmi_container::set_item(const std::string& id, const vconfig& menu_item)
179 {
180  // Try to insert a dummy value. This combines looking for an existing
181  // entry with insertion.
182  map_t::iterator add_it = wml_menu_items_.insert(map_t::value_type(id, item_ptr())).first;
183 
184  if ( add_it->second )
185  // Create a new menu item based on the old. This leaves the old item
186  // alone in case someone else is holding on to (and processing) it.
187  add_it->second.reset(new wml_menu_item(id, menu_item, *add_it->second));
188  else
189  // This is a new menu item.
190  add_it->second.reset(new wml_menu_item(id, menu_item));
191 }
192 
193 /**
194  * Sets the current menu items to the "menu_item" children of @a cfg.
195  */
197 {
198  wml_menu_items_.clear();
199  for (const config &item : cfg.child_range("menu_item"))
200  {
201  if(!item.has_attribute("id")){ continue; }
202 
203  std::string id = item["id"];
204  item_ptr & mref = wml_menu_items_[id];
205  if ( !mref ) {
206  mref.reset(new wml_menu_item(id, item));
207  } else {
208  WRN_NG << "duplicate menu item (" << id << ") while loading from config" << std::endl;
209  }
210  }
211 }
212 
213 } // end namespace game_events
214 
play_controller * controller
Definition: resources.cpp:21
child_itors child_range(const std::string &key)
Definition: config.cpp:613
static lg::log_domain log_engine("engine")
bool empty() const
Returns true if *this contains no data.
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.
#define WRN_NG
bool can_use_synced_wml_menu() const
Definitions for the interface to Wesnoth Markup Language (WML).
iterator find(const std::string &id)
Returns an iterator to a menu item with the given id, if one exists.
#define LOG_NG
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:70
map_t::size_type size_type
GLuint id
Definition: glew.h:1647
void to_config(config &cfg) const
GLuint start
Definition: glew.h:1221
boost::shared_ptr< wml_menu_item > item_ptr
Pointers to our elements.
config & add_child(const std::string &key)
Definition: config.cpp:743
void set_menu_items(const config &cfg)
Sets the current menu items to the "menu_item" children of cfg.
bool can_show(const map_location &hex, const game_data &data, filter_context &context) const
Returns whether or not *this is applicable given the context.
Definition: menu_item.cpp:174
Encapsulates the map of the game.
Definition: location.hpp:38
Domain specific events.
Definition: action_wml.cpp:93
Declarations for a container for wml_menu_item.
std::vector< std::pair< boost::shared_ptr< const wml_menu_item >, std::string > > get_items(const map_location &hex, game_data &gamedata, filter_context &fc, unit_map &units, const_iterator start, const_iterator finish) const
Returns the menu items that can be shown for the given location.
void fire_event(const map_location &event_hex, const game_data &data) const
Causes the event associated with this item to fire.
Definition: menu_item.cpp:203
Define the handlers for the game's events mechanism.
void init_handlers() const
Initializes the implicit event handlers for inlined [command]s.
A variable-expanding proxy for the config class.
Definition: variable.hpp:36
Standard logging facilities (interface).
Container associating units to locations.
Definition: map.hpp:90
void set_item(const std::string &id, const vconfig &menu_item)
Updates or creates (as appropriate) the menu item with the given id.
This is a const_iterator class that extends an existing const_iterator by overriding dereference...
Definition: iterator.hpp:27
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
GLsizei const GLcharARB ** string
Definition: glew.h:4503
unit_map * units
Definition: resources.cpp:35
size_type erase(const std::string &id)
Erases the item with the provided id.