The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
wmi_pager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2014 - 2016 by Chris Beck <[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 #include "wmi_pager.hpp"
17 #include "global.hpp"
18 
19 #include "config.hpp"
22 #include "game_preferences.hpp"
23 #include "gettext.hpp"
24 
25 #include <algorithm> //std::transform
26 #include <boost/make_shared.hpp>
27 #include <boost/shared_ptr.hpp>
28 #include <cassert>
29 #include <iterator> //std::advance
30 #include <string>
31 #include <vector>
32 
33 struct map_location;
34 
35 static const char * next_id = "__wml_items_next_page";
36 static const char * prev_id = "__wml_items_prev_page";
37 
39  std::vector<std::string> & descriptions)
40 {
41  std::string desc = _("More Items");
42  config temp;
43  temp["description"] = desc;
44  items.push_back(boost::make_shared<const game_events::wml_menu_item>(next_id, temp));
45  descriptions.push_back(desc);
46 }
47 
49  std::vector<std::string> & descriptions)
50 {
51  std::string desc = _("Previous Items");
52  config temp;
53  temp["description"] = desc;
54  items.push_back(boost::make_shared<const game_events::wml_menu_item>(prev_id, temp));
55  descriptions.push_back(desc);
56 }
57 
59 {
60  if (item.id() == next_id) {
61  page_num_++;
62  return true;
63  } else if (item.id() == prev_id) {
64  page_num_--;
65  return true;
66  }
67  return false;
68 }
69 
71 typedef std::pair<wmi_ptr, std::string> wmi_pair;
73 
74 static wmi_ptr select_first(const wmi_pair & p)
75 {
76  return p.first;
77 }
78 
80 {
81  return p.second;
82 }
83 
86  std::vector<wmi_ptr > & items,
87  std::vector<std::string> & descriptions)
88 {
89  if (!wmi_container_) {
90  return;
91  }
92 
93  const int page_size_int = preferences::max_wml_menu_items();
94 
95  assert(page_size_int >= 0 && "max wml menu items cannot be negative, this indicates preferences corruption");
96 
97  const size_t page_size = page_size_int;
98 
99  assert(page_size > 2u && "if we dont have at least 3 items, we can't display anything on a middle page...");
100 
101  std::vector<wmi_pair > new_items = wmi_container_->get_items(hex, gamedata, fc, units);
102 
103  if (new_items.size() <= page_size) { //In this case the first page is sufficient and we don't have to do anything.
104  std::transform(new_items.begin(), new_items.end(), back_inserter(items), select_first);
105  std::transform(new_items.begin(), new_items.end(), back_inserter(descriptions), select_second);
106 
107  page_num_ = 0; //reset page num in case there are more items later.
108  return;
109  }
110 
111  if (page_num_ < 0) //should never happen but maybe some wierd gui thing happens idk
112  {
113  page_num_ = 0;
114  }
115 
116  if (page_num_ == 0) { //we are on the first page, so show page_size-1 items and a next button
117  wmi_it end_first_page = new_items.begin();
118  std::advance(end_first_page, page_size - 1);
119 
120  std::transform(new_items.begin(), end_first_page, back_inserter(items), select_first);
121  std::transform(new_items.begin(), end_first_page, back_inserter(descriptions), select_second);
122 
123  add_next_page_item(items, descriptions);
124  return;
125  }
126 
127  add_prev_page_item(items, descriptions); //this will be necessary since we aren't on the first page
128 
129  // first page has page_size - 1.
130  // last page has page_size - 1.
131  // all other pages have page_size - 2;
132 
133  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.
134  //alternatively, the number of items displayed on earlier pages
135 
136  while (first_displayed_index >= new_items.size())
137  {
138  page_num_--; //The list must have gotten shorter and our page counter is now off the end, so decrement
139  first_displayed_index = (page_size - 2) * page_num_ + 1; //recalculate
140  }
141  // ^ This loop terminates with first_displayed_index > 0, because new_items.size() > page_size or else we exited earlier, and we only decrease by (page_size-2) each time.
142 
143  if (first_displayed_index + page_size-1 >= new_items.size()) //if this can be the last page, then we won't put next page at the bottom.
144  {
145  //The last page we treat differently -- we always want to display (page_size) entries, to prevent resizing the context menu, so count back from end.
146  wmi_it end_range = new_items.end(); // It doesn't really matter if we display some entries that appeared on the previous page by doing this.
147  wmi_it start_range = end_range;
148  std::advance(start_range, -static_cast<signed int>(page_size-1));
149 
150  std::transform(start_range, end_range, back_inserter(items), select_first);
151  std::transform(start_range, end_range, back_inserter(descriptions), select_second);
152  return;
153  } else { //we are in a middle page
154  wmi_it start_range = new_items.begin();
155  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
156 
157  wmi_it end_range = start_range;
158  std::advance(end_range, page_size-2);
159 
160  std::transform(start_range, end_range, back_inserter(items), select_first);
161  std::transform(start_range, end_range, back_inserter(descriptions), select_second);
162 
163  add_next_page_item(items, descriptions);
164  return;
165  }
166 }
boost::shared_ptr< const game_events::wml_menu_item > wmi_ptr
Definition: wmi_pager.cpp:70
static wmi_ptr select_first(const wmi_pair &p)
Definition: wmi_pager.cpp:74
static void add_next_page_item(std::vector< boost::shared_ptr< const game_events::wml_menu_item > > &items, std::vector< std::string > &descriptions)
Definition: wmi_pager.cpp:38
static const char * prev_id
Definition: wmi_pager.cpp:36
const std::vector< std::string > items
std::pair< wmi_ptr, std::string > wmi_pair
Definition: wmi_pager.cpp:71
Definitions for the interface to Wesnoth Markup Language (WML).
game_data * gamedata
Definition: resources.cpp:22
GLuint GLenum GLenum transform
Definition: glew.h:11418
const game_events::wmi_container * wmi_container_
Internal pointer to the collection of wml menu items.
Definition: wmi_pager.hpp:42
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
int page_num_
Current page number.
Definition: wmi_pager.hpp:41
GLfloat GLfloat p
Definition: glew.h:12766
Encapsulates the map of the game.
Definition: location.hpp:38
Declarations for a container for wml_menu_item.
static std::string select_second(const wmi_pair &p)
Definition: wmi_pager.cpp:79
void get_items(const map_location &hex, game_data &gamedata, filter_context &fc, unit_map &units, std::vector< boost::shared_ptr< const game_events::wml_menu_item > > &items, std::vector< std::string > &descriptions)
Adds the currently paged range of menu items to the given lists.
Definition: wmi_pager.cpp:84
static void add_prev_page_item(std::vector< boost::shared_ptr< const game_events::wml_menu_item > > &items, std::vector< std::string > &descriptions)
Definition: wmi_pager.cpp:48
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.
static const char * next_id
Definition: wmi_pager.cpp:35
Container associating units to locations.
Definition: map.hpp:90
std::vector< wmi_pair >::iterator wmi_it
Definition: wmi_pager.cpp:72
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
bool capture(const game_events::wml_menu_item &item)
Captures a page up / page down event in the case that it is fired.
Definition: wmi_pager.cpp:58
GLsizei const GLcharARB ** string
Definition: glew.h:4503
unit_map * units
Definition: resources.cpp:35
const std::string & id() const
The id of this item.
Definition: menu_item.hpp:47