The Battle for Wesnoth  1.17.0-dev
help_menu.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2021
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "help/help_menu.hpp"
17 
18 #include "game_config.hpp" // for menu_contract, menu_expand
19 #include "help/help_impl.hpp" // for section, topic, topic_list, etc
20 #include "sound.hpp" // for play_UI_sound
21 #include "wml_separators.hpp" // for IMG_TEXT_SEPARATOR, etc
22 
23 #include <algorithm> // for find
24 #include <iostream> // for basic_ostream, operator<<, etc
25 #include <list> // for _List_const_iterator, etc
26 #include <utility> // for pair
27 #include <SDL2/SDL.h>
28 
29 class CVideo; // lines 56-56
30 
31 namespace help {
32 
33 help_menu::help_menu(CVideo &video, const section& toplevel, int max_height) :
34  gui::menu(video, empty_string_vector, true, max_height, -1, nullptr, &gui::menu::bluebg_style),
35  visible_items_(),
36  toplevel_(toplevel),
37  expanded_(),
38  restorer_(),
39  chosen_topic_(nullptr),
40  selected_item_(&toplevel, "", 0)
41 {
42  silent_ = true; //silence the default menu sounds
45  if (!visible_items_.empty())
47 }
48 
49 bool help_menu::expanded(const section &sec)
50 {
51  return expanded_.find(&sec) != expanded_.end();
52 }
53 
54 void help_menu::expand(const section &sec)
55 {
56  if (sec.id != "toplevel" && expanded_.insert(&sec).second) {
58  }
59 }
60 
61 void help_menu::contract(const section &sec)
62 {
63  if (expanded_.erase(&sec)) {
65  }
66 }
67 
68 void help_menu::update_visible_items(const section &sec, unsigned level)
69 {
70  if (level == 0) {
71  // Clear if this is the top level, otherwise append items.
72  visible_items_.clear();
73  }
74  for (const auto &s : sec.sections) {
75  if (is_visible_id(s.id)) {
76  const std::string vis_string = get_string_to_show(s, level + 1);
77  visible_items_.emplace_back(&s, vis_string, level + 1);
78  if (expanded(s)) {
79  update_visible_items(s, level + 1);
80  }
81  }
82  }
83  for (const auto &t : sec.topics) {
84  if (is_visible_id(t.id)) {
85  const std::string vis_string = get_string_to_show(t, level + 1);
86  visible_items_.emplace_back(&t, vis_string, level + 1);
87  }
88  }
89 }
90 
91 std::string help_menu::indent_list(const std::string& icon, const unsigned level) {
92  std::stringstream to_show;
93  for (unsigned i = 1; i < level; ++i) {
94  to_show << " "; // Indent 4 spaces
95  }
96 
97  to_show << IMG_TEXT_SEPARATOR << IMAGE_PREFIX << icon;
98  return to_show.str();
99 }
100 
101 std::string help_menu::get_string_to_show(const section &sec, const unsigned level)
102 {
103  std::stringstream to_show;
104  to_show << indent_list(expanded(sec) ? open_section_img : closed_section_img, level)
105  << IMG_TEXT_SEPARATOR << sec.title;
106  return to_show.str();
107 }
108 
109 std::string help_menu::get_string_to_show(const topic &topic, const unsigned level)
110 {
111  std::stringstream to_show;
112  to_show << indent_list(topic_img, level)
113  << IMG_TEXT_SEPARATOR << topic.title;
114  return to_show.str();
115 }
116 
118 {
119  topic_list::const_iterator tit =
120  std::find(sec.topics.begin(), sec.topics.end(), t);
121  if (tit != sec.topics.end()) {
122  // topic starting with ".." are assumed as rooted in the parent section
123  // and so only expand the parent when selected
124  if (t.id.size()<2 || t.id[0] != '.' || t.id[1] != '.')
125  expand(sec);
126  return true;
127  }
128  for (const auto &s : sec.sections) {
129  if (select_topic_internal(t, s)) {
130  expand(sec);
131  return true;
132  }
133  }
134  return false;
135 }
136 
138 {
139  if (selected_item_ == t) {
140  // The requested topic is already selected.
141  return;
142  }
145  for (std::vector<visible_item>::const_iterator it = visible_items_.begin();
146  it != visible_items_.end(); ++it) {
147  if (*it == t) {
148  selected_item_ = *it;
149  break;
150  }
151  }
153  }
154 }
155 
157 {
158  int res = menu::process();
159  int mousex, mousey;
160  SDL_GetMouseState(&mousex,&mousey);
161 
162  if (!visible_items_.empty() &&
163  static_cast<std::size_t>(res) < visible_items_.size()) {
164 
166  const section* sec = selected_item_.sec;
167  if (sec != nullptr) {
168  // Behavior of the UI, for section headings:
169  // * user single-clicks on the text part: show the ".." topic in the right-hand pane
170  // * user single-clicks on the icon (or to the left of it): expand or collapse the tree view
171  // * user double-clicks anywhere: expand or collapse the tree view
172  // * note: the first click of the double-click has the single-click effect too
173  int x = mousex - menu::location().x;
174 
175  const std::string icon_img = expanded(*sec) ? open_section_img : closed_section_img;
176  // the "thickness" is the width of the left border
177  int text_start = style_->item_size(indent_list(icon_img, selected_item_.level)).w - style_->get_thickness();
178 
179  // NOTE: if you want to forbid click to the left of the icon
180  // also check x >= text_start-image_width(icon_img)
181  if (menu::double_clicked() || x < text_start) {
182  // Open or close a section if we double-click on it
183  // or do simple click on the icon.
184  expanded(*sec) ? contract(*sec) : expand(*sec);
187  } else if (x >= text_start){
188  // click on title open the topic associated to this section
190  }
191  } else if (selected_item_.t != nullptr) {
192  // Choose a topic if it is clicked.
194  }
195  }
196  return res;
197 }
198 
200 {
201  const topic *ret = chosen_topic_;
202  chosen_topic_ = nullptr;
203  return ret;
204 }
205 
207 {
208  std::vector<std::string> menu_items;
209  for(std::vector<visible_item>::const_iterator items_it = visible_items_.begin(),
210  end = visible_items_.end(); items_it != end; ++items_it) {
211  std::string to_show = items_it->visible_string;
212  if (selected_item_ == *items_it)
213  to_show = std::string("*") + to_show;
214  menu_items.push_back(to_show);
215  }
216  set_items(menu_items, false, true);
217 }
218 
219 help_menu::visible_item::visible_item(const section *_sec, const std::string &vis_string, int lev) :
220  t(nullptr), sec(_sec), visible_string(vis_string), level(lev) {}
221 
222 help_menu::visible_item::visible_item(const topic *_t, const std::string &vis_string, int lev) :
223  t(_t), sec(nullptr), visible_string(vis_string), level(lev) {}
224 
226 {
227  return sec != nullptr && *sec == _sec;
228 }
229 
231 {
232  return t != nullptr && *t == _t;
233 }
234 
236 {
237  return t == vis_item.t && sec == vis_item.sec;
238 }
239 
240 } // end namespace help
void contract(const section &sec)
Contract (close) a section.
Definition: help_menu.cpp:61
std::string get_string_to_show(const section &sec, const unsigned level)
Return the string to use as the menu-string for sections at the specified level.
Definition: help_menu.cpp:101
char const IMG_TEXT_SEPARATOR
std::string id
Definition: help_impl.hpp:164
const std::string open_section_img
Definition: help_impl.cpp:86
const std::string topic_img
Definition: help_impl.cpp:84
visible_item selected_item_
Definition: help_menu.hpp:109
topic const * chosen_topic_
Definition: help_menu.hpp:108
const std::string closed_section_img
Definition: help_impl.cpp:85
A section contains topics and sections along with title and ID.
Definition: help_impl.hpp:146
const std::string menu_expand
Definition: video.hpp:32
General purpose widgets.
virtual SDL_Rect item_size(const std::string &item) const
Definition: menu.cpp:746
std::vector< std::string > empty_string_vector
Definition: help_impl.cpp:77
bool expanded(const section &sec)
Return true if the section is expanded.
Definition: help_menu.cpp:49
visible_item(const section *_sec, const std::string &visible_string, int level)
Definition: help_menu.cpp:219
bool is_visible_id(const std::string &id)
Definition: help_impl.cpp:1519
char const IMAGE_PREFIX
section_list sections
Definition: help_impl.hpp:166
std::string id
Definition: help_impl.hpp:137
void process(int mousex, int mousey)
Definition: tooltips.cpp:194
void display_visible_items()
Draw the currently visible items.
Definition: help_menu.cpp:206
std::string title
Definition: help_impl.hpp:164
const section & toplevel_
Definition: help_menu.hpp:105
std::string indent_list(const std::string &icon, const unsigned level)
Return the string to use as the prefix for the icon part of the menu-string at the specified level...
Definition: help_menu.cpp:91
Information about an item that is visible in the menu.
Definition: help_menu.hpp:56
void expand(const section &sec)
Mark a section as expanded.
Definition: help_menu.cpp:54
help_menu(CVideo &video, const section &toplevel, int max_height=-1)
Definition: help_menu.cpp:33
virtual void set_items(const std::vector< std::string > &items, bool strip_spaces=true, bool keep_viewport=false)
Set new items to show and redraw/recalculate everything.
Definition: menu.cpp:389
std::set< const section * > expanded_
Definition: help_menu.hpp:106
std::size_t i
Definition: function.cpp:967
static map_location::DIRECTION s
std::vector< visible_item > visible_items_
Definition: help_menu.hpp:104
const std::string menu_contract
bool operator==(const visible_item &vis_item) const
Definition: help_menu.cpp:235
void select_topic(const topic &t)
Make the topic the currently selected one, and expand all sections that need to be expanded to show i...
Definition: help_menu.cpp:137
double t
Definition: astarsearch.cpp:65
const topic * find_topic(const section &sec, const std::string &id)
Search for the topic with the specified identifier in the section and its subsections.
Definition: help_impl.cpp:1216
void play_UI_sound(const std::string &files)
Definition: sound.cpp:1052
A topic contains a title, an id and some text.
Definition: help_impl.hpp:112
void update_visible_items(const section &top_level, unsigned starting_level=0)
Regenerate what items are visible by checking what sections are expanded.
Definition: help_menu.cpp:68
const topic * chosen_topic()
If a topic has been chosen, return that topic, otherwise nullptr.
Definition: help_menu.cpp:199
bool silent_
Definition: menu.hpp:216
Definition: help.cpp:57
std::string title
Definition: help_impl.hpp:137
bool select_topic_internal(const topic &t, const section &sec)
Internal recursive thingie.
Definition: help_menu.cpp:117
topic_list topics
Definition: help_impl.hpp:165
style * style_
Definition: menu.hpp:215
std::size_t get_thickness() const
Definition: menu_style.cpp:58
help::section default_toplevel
Definition: help_impl.cpp:69