diff --git a/projectfiles/CodeBlocks/wesnoth.cbp b/projectfiles/CodeBlocks/wesnoth.cbp
index e22212fc163b..a1fec4f42b5b 100644
--- a/projectfiles/CodeBlocks/wesnoth.cbp
+++ b/projectfiles/CodeBlocks/wesnoth.cbp
@@ -1123,6 +1123,8 @@
+
+
diff --git a/projectfiles/VC9/wesnoth.vcproj b/projectfiles/VC9/wesnoth.vcproj
index 5f79bf2aff65..3826354dd26a 100644
--- a/projectfiles/VC9/wesnoth.vcproj
+++ b/projectfiles/VC9/wesnoth.vcproj
@@ -21288,6 +21288,14 @@
RelativePath="..\..\src\notifications\windows_tray_notification.hpp"
>
+
+
+
+
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 36fe06ab6596..0b64b3a8a103 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -916,6 +916,7 @@ set(wesnoth-main_SRC
whiteboard/side_actions.cpp
whiteboard/suppose_dead.cpp
whiteboard/utility.cpp
+ wmi_pager.cpp
${network_implementation_files} # network.cpp and network_worker.cpp are included by default (without USE_ANA_NETWORK)
)
diff --git a/src/SConscript b/src/SConscript
index 5f0e2398967e..8acc52c4dced 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -553,6 +553,7 @@ wesnoth_sources = Split("""
widgets/combo_drag.cpp
widgets/drop_target.cpp
widgets/scrollpane.cpp
+ wmi_pager.cpp
""")
if env["PLATFORM"] == "win32":
diff --git a/src/game_events/menu_item.hpp b/src/game_events/menu_item.hpp
index e6904472d18b..937dee2991ad 100644
--- a/src/game_events/menu_item.hpp
+++ b/src/game_events/menu_item.hpp
@@ -41,6 +41,8 @@ class wml_menu_item
wml_menu_item(const std::string& id, const vconfig & definition,
const wml_menu_item & original);
+ /// The id of this item.
+ const std::string & id() const { return item_id_; }
/// The image associated with this menu item.
const std::string & image() const;
/// If true, allow using the menu to trigger this item.
diff --git a/src/game_events/wmi_container.cpp b/src/game_events/wmi_container.cpp
index 0e6848c0e5e6..d8188188d82e 100644
--- a/src/game_events/wmi_container.cpp
+++ b/src/game_events/wmi_container.cpp
@@ -34,9 +34,6 @@ static lg::log_domain log_engine("engine");
#define WRN_NG LOG_STREAM(warn, log_engine)
#define LOG_NG LOG_STREAM(info, log_engine)
-static const size_t MAX_WML_COMMANDS = 7;
-
-
// This file is in the game_events namespace.
namespace game_events
{
@@ -104,16 +101,14 @@ bool wmi_container::fire_item(const std::string & id, const map_location & hex)
/**
* Returns the menu items that can be shown for the given location.
- * The number of items returned is limited by MAX_WML_COMMANDS.
+ * Should be used with a wmi_pager to limit the number of items displayed at once.
* @param[out] items Pointers to applicable menu items will be pushed onto @a items.
* @param[out] descriptions Menu item text will be pushed onto @descriptions (in the same order as @a items).
*/
void wmi_container::get_items(const map_location& hex,
std::vector > & items,
- std::vector & descriptions) const
+ std::vector & descriptions, const_iterator start, const_iterator finish) const
{
- size_t item_count = 0;
-
if ( empty() )
// Nothing to do (skip setting game variables).
return;
@@ -124,7 +119,7 @@ void wmi_container::get_items(const map_location& hex,
scoped_xy_unit highlighted_unit("unit", hex.x, hex.y, *resources::units);
// Check each menu item.
- BOOST_FOREACH( const item_ptr & item, *this )
+ BOOST_FOREACH( const item_ptr & item, std::make_pair (start, finish) )
{
// Can this item be shown?
if ( item->use_wml_menu() && item->can_show(hex) )
@@ -132,10 +127,6 @@ void wmi_container::get_items(const map_location& hex,
// Include this item.
items.push_back(item);
descriptions.push_back(item->menu_text());
-
- // Limit how many items can be returned.
- if ( ++item_count >= MAX_WML_COMMANDS )
- return;
}
}
}
diff --git a/src/game_events/wmi_container.hpp b/src/game_events/wmi_container.hpp
index 02f28e566b7e..c8a6167927be 100644
--- a/src/game_events/wmi_container.hpp
+++ b/src/game_events/wmi_container.hpp
@@ -76,8 +76,15 @@ class wmi_container{
bool fire_item(const std::string & id, const map_location & hex) const;
/// Returns the menu items that can be shown for the given location.
void get_items(const map_location& hex,
- std::vector > & items,
- std::vector & descriptions) const;
+ std::vector > & items,
+ std::vector & descriptions,
+ const_iterator start, const_iterator finish) const;
+ /// Range over all items by default
+ void get_items(const map_location& hex,
+ std::vector > & items,
+ std::vector & descriptions) const {
+ get_items(hex, items, descriptions, begin(), end());
+ }
/// Initializes the implicit event handlers for inlined [command]s.
void init_handlers() const;
void to_config(config& cfg) const;
@@ -99,6 +106,7 @@ class wmi_container{
const_iterator begin() const { return const_iterator(wml_menu_items_.begin()); }
const_iterator end() const { return const_iterator(wml_menu_items_.end()); }
+ size_t size() const { return wml_menu_items_.size(); }
private: // data
map_t wml_menu_items_;
};
diff --git a/src/play_controller.cpp b/src/play_controller.cpp
index 5a69da83bcc8..f16f071061d2 100644
--- a/src/play_controller.cpp
+++ b/src/play_controller.cpp
@@ -54,6 +54,7 @@
#include "unit.hpp"
#include "unit_id.hpp"
#include "whiteboard/manager.hpp"
+#include "wmi_pager.hpp"
#include "wml_exception.hpp"
#include
@@ -125,6 +126,7 @@ play_controller::play_controller(const config& level, saved_game& state_of_game,
init_side_done_(level["init_side_done"].to_bool(true)),
savenames_(),
wml_commands_(),
+ wml_command_pager_(new wmi_pager()),
victory_when_enemies_defeated_(true),
remove_from_carryover_on_defeat_(true),
end_level_data_(),
@@ -724,7 +726,9 @@ bool play_controller::execute_command(const hotkey::hotkey_command& cmd, int ind
throw game::load_game_exception(savenames_[i],false,false,false,"");
} else if ( i < wml_commands_.size() && wml_commands_[i] ) {
- wml_commands_[i]->fire_event(mouse_handler_.get_last_hex());
+ if (!wml_command_pager_->capture(*wml_commands_[i])) {
+ wml_commands_[i]->fire_event(mouse_handler_.get_last_hex());
+ }
return true;
}
}
@@ -1072,7 +1076,8 @@ void play_controller::expand_wml_commands(std::vector& items)
// Replace this placeholder entry with available menu items.
items.erase(items.begin() + i);
- gamestate_.gamedata_.get_wml_menu_items().get_items(mouse_handler_.get_last_hex(),
+ wml_command_pager_->update_ref(&gamestate_.gamedata_.get_wml_menu_items());
+ wml_command_pager_->get_items(mouse_handler_.get_last_hex(),
wml_commands_, newitems);
items.insert(items.begin()+i, newitems.begin(), newitems.end());
// End the "for" loop.
diff --git a/src/play_controller.hpp b/src/play_controller.hpp
index 7a1e7ab4fb80..f7a632e78856 100644
--- a/src/play_controller.hpp
+++ b/src/play_controller.hpp
@@ -35,6 +35,7 @@ class saved_game;
class game_data;
class team;
class unit;
+class wmi_pager;
namespace actions {
class undo_list;
@@ -279,6 +280,7 @@ class play_controller : public controller_base, public events::observer, public
void expand_wml_commands(std::vector& items);
std::vector wml_commands_;
+ boost::scoped_ptr wml_command_pager_;
bool victory_when_enemies_defeated_;
bool remove_from_carryover_on_defeat_;
diff --git a/src/wmi_pager.cpp b/src/wmi_pager.cpp
new file mode 100644
index 000000000000..dceb0987a1a0
--- /dev/null
+++ b/src/wmi_pager.cpp
@@ -0,0 +1,131 @@
+/*
+ Copyright (C) 2014 by Chris Beck
+ Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY.
+
+ See the COPYING file for more details.
+*/
+
+
+#include "wmi_pager.hpp"
+#include "global.hpp"
+
+#include "config.hpp"
+#include "game_events/menu_item.hpp"
+#include "game_events/wmi_container.hpp"
+#include "gettext.hpp"
+
+#include
+#include
+#include //std::advance
+#include
+#include
+
+struct map_location;
+
+static const char * next_id = "__wml_items_next_page";
+static const char * prev_id = "__wml_items_prev_page";
+
+static void add_next_page_item( std::vector > & items,
+ std::vector & descriptions)
+{
+ std::string desc = _("More Items");
+ config temp;
+ temp["description"] = desc;
+ items.push_back(boost::make_shared(next_id, temp));
+ descriptions.push_back(desc);
+}
+
+static void add_prev_page_item( std::vector > & items,
+ std::vector & descriptions)
+{
+ std::string desc = _("Earlier Items");
+ config temp;
+ temp["description"] = desc;
+ items.push_back(boost::make_shared(prev_id, temp));
+ descriptions.push_back(desc);
+}
+
+bool wmi_pager::capture ( const game_events::wml_menu_item & item )
+{
+ if (item.id() == next_id) {
+ page_num_++;
+ return true;
+ } else if (item.id() == prev_id) {
+ page_num_--;
+ return true;
+ }
+ return false;
+}
+
+typedef game_events::wmi_container::const_iterator wmi_it;
+
+void wmi_pager::get_items(const map_location& hex,
+ std::vector > & items,
+ std::vector & descriptions)
+{
+ if (!foo_) {
+ return;
+ }
+
+ assert(page_size_ > 2u); //if we dont have at least 3 items, we can't display anything...
+
+ if (foo_->size() <= page_size_) { //In this case the first page is sufficient and we don't have to do anything.
+ foo_->get_items(hex, items, descriptions);
+ page_num_ = 0; //reset page num in case there are more items later.
+ return;
+ }
+
+ if (page_num_ < 0) //should never happen but maybe some wierd gui thing happens idk
+ {
+ page_num_ = 0;
+ }
+
+ if (page_num_ == 0) { //we are on the first page, so show page_size_-1 items and a next button
+ wmi_it end_first_page = foo_->begin();
+ std::advance(end_first_page, page_size_ - 1);
+
+ foo_->get_items(hex, items, descriptions, foo_->begin(), end_first_page);
+ add_next_page_item(items, descriptions);
+ return;
+ }
+
+ add_prev_page_item(items, descriptions); //this will be necessary since we aren't on the first page
+
+ // first page has page_size_ - 1.
+ // last page has page_size_ - 1.
+ // all other pages have page_size_ - 2;
+
+ size_t first_displayed_index = (page_size_ - 2) * page_num_ + 1; //this is the 0-based index of the first item displayed on this page.
+ //alternatively, the number of items displayed on earlier pages
+
+ while (first_displayed_index >= foo_->size())
+ {
+ page_num_--; //The list must have gotten shorter and our page counter is now off the end, so decrement
+ first_displayed_index = (page_size_ - 2) * page_num_ + 1; //recalculate
+ }
+ // ^ This loop terminates with first_displayed_index > 0, because foo_->size() > page_size_ or else we exited earlier, and we only decrease by (page_size_-2) each time.
+
+ wmi_it start_range = foo_->begin();
+ std::advance(start_range, first_displayed_index); // <-- get an iterator to the start of our range. begin() + n doesn't work because map is not random access
+ //^ = foo_->begin() + first_displayed_index
+
+ if (first_displayed_index + page_size_-1 >= foo_->size()) //if this can be the last page, then we won't put next page at the bottom.
+ {
+ foo_->get_items(hex, items, descriptions, start_range, foo_->end()); // display all of the remaining items
+ return;
+ } else { //we are in a middle page
+ wmi_it end_range = start_range;
+ std::advance(end_range, page_size_-2);
+
+ foo_->get_items(hex, items, descriptions, start_range, end_range);
+ add_next_page_item(items, descriptions);
+ return;
+ }
+}
diff --git a/src/wmi_pager.hpp b/src/wmi_pager.hpp
new file mode 100644
index 000000000000..86276f8e083e
--- /dev/null
+++ b/src/wmi_pager.hpp
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2014 by Chris Beck
+ Part of the Battle for Wesnoth Project http://www.wesnoth.org/
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY.
+
+ See the COPYING file for more details.
+*/
+
+
+/** This class manages the paging of WML menu items results, from a
+ * container. It is an adapter, managing the production of items lists
+ * from the container, and screening the "fire" signals coming back
+ * in to intercept the paging signals.
+ */
+
+struct map_location;
+namespace game_events { class wml_menu_item; }
+namespace game_events { class wmi_container; }
+
+#include "global.hpp"
+
+#include
+#include
+#include
+
+class wmi_pager {
+private:
+ int page_num_; //!< Current page number
+ size_t page_size_; //!< Current size of a page
+ const game_events::wmi_container * foo_; //!< Internal pointer to the collection of wml menu items
+
+public:
+ wmi_pager() : page_num_(0), page_size_(7), foo_(NULL) {}
+
+ void update_ref(game_events::wmi_container * ptr) { foo_ = ptr; } //!< Updates the internal wmi_container pointer
+
+ /** Adds the currently paged range of menu items to the given lists */
+ void get_items(const map_location& hex, //!< Game hex related to this context menu
+ std::vector > & items, //!< List of accumulated menu items so far.
+ std::vector & descriptions); //!< List of menu item descriptions
+
+ bool capture(const game_events::wml_menu_item & item); //!< Captures a page up / page down event in the case that it is fired.
+};