The Battle for Wesnoth  1.17.4+dev
help_menu.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2022
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 #include "sdl/input.hpp" // for get_mouse_state
23 
24 #include <algorithm> // for find
25 #include <iostream> // for basic_ostream, operator<<, etc
26 #include <list> // for _List_const_iterator, etc
27 #include <utility> // for pair
28 #include <SDL2/SDL.h>
29 
30 class CVideo; // lines 56-56
31 
32 namespace help {
33 
34 help_menu::help_menu(CVideo &video, const section& toplevel, int max_height) :
35  gui::menu(video, empty_string_vector, true, max_height, -1, nullptr, &gui::menu::bluebg_style),
36  visible_items_(),
37  toplevel_(toplevel),
38  expanded_(),
39  restorer_(),
40  chosen_topic_(nullptr),
41  selected_item_(&toplevel, "", 0)
42 {
43  silent_ = true; //silence the default menu sounds
46  if (!visible_items_.empty())
48 }
49 
50 bool help_menu::expanded(const section &sec)
51 {
52  return expanded_.find(&sec) != expanded_.end();
53 }
54 
55 void help_menu::expand(const section &sec)
56 {
57  if (sec.id != "toplevel" && expanded_.insert(&sec).second) {
59  }
60 }
61 
62 void help_menu::contract(const section &sec)
63 {
64  if (expanded_.erase(&sec)) {
66  }
67 }
68 
69 void help_menu::update_visible_items(const section &sec, unsigned level)
70 {
71  if (level == 0) {
72  // Clear if this is the top level, otherwise append items.
73  visible_items_.clear();
74  }
75  for (const auto &s : sec.sections) {
76  if (is_visible_id(s.id)) {
77  const std::string vis_string = get_string_to_show(s, level + 1);
78  visible_items_.emplace_back(&s, vis_string, level + 1);
79  if (expanded(s)) {
80  update_visible_items(s, level + 1);
81  }
82  }
83  }
84  for (const auto &t : sec.topics) {
85  if (is_visible_id(t.id)) {
86  const std::string vis_string = get_string_to_show(t, level + 1);
87  visible_items_.emplace_back(&t, vis_string, level + 1);
88  }
89  }
90 }
91 
92 std::string help_menu::indent_list(const std::string& icon, const unsigned level) {
93  std::stringstream to_show;
94  for (unsigned i = 1; i < level; ++i) {
95  to_show << " "; // Indent 4 spaces
96  }
97 
98  to_show << IMG_TEXT_SEPARATOR << IMAGE_PREFIX << icon;
99  return to_show.str();
100 }
101 
102 std::string help_menu::get_string_to_show(const section &sec, const unsigned level)
103 {
104  std::stringstream to_show;
105  to_show << indent_list(expanded(sec) ? open_section_img : closed_section_img, level)
106  << IMG_TEXT_SEPARATOR << sec.title;
107  return to_show.str();
108 }
109 
110 std::string help_menu::get_string_to_show(const topic &topic, const unsigned level)
111 {
112  std::stringstream to_show;
113  to_show << indent_list(topic_img, level)
114  << IMG_TEXT_SEPARATOR << topic.title;
115  return to_show.str();
116 }
117 
119 {
120  topic_list::const_iterator tit =
121  std::find(sec.topics.begin(), sec.topics.end(), t);
122  if (tit != sec.topics.end()) {
123  // topic starting with ".." are assumed as rooted in the parent section
124  // and so only expand the parent when selected
125  if (t.id.size()<2 || t.id[0] != '.' || t.id[1] != '.')
126  expand(sec);
127  return true;
128  }
129  for (const auto &s : sec.sections) {
130  if (select_topic_internal(t, s)) {
131  expand(sec);
132  return true;
133  }
134  }
135  return false;
136 }
137 
139 {
140  if (selected_item_ == t) {
141  // The requested topic is already selected.
142  return;
143  }
146  for (std::vector<visible_item>::const_iterator it = visible_items_.begin();
147  it != visible_items_.end(); ++it) {
148  if (*it == t) {
149  selected_item_ = *it;
150  break;
151  }
152  }
154  }
155 }
156 
158 {
159  int res = menu::process();
160  int mousex, mousey;
161  sdl::get_mouse_state(&mousex, &mousey);
162 
163  if (!visible_items_.empty() &&
164  static_cast<std::size_t>(res) < visible_items_.size()) {
165 
167  const section* sec = selected_item_.sec;
168  if (sec != nullptr) {
169  // Behavior of the UI, for section headings:
170  // * user single-clicks on the text part: show the ".." topic in the right-hand pane
171  // * user single-clicks on the icon (or to the left of it): expand or collapse the tree view
172  // * user double-clicks anywhere: expand or collapse the tree view
173  // * note: the first click of the double-click has the single-click effect too
174  int x = mousex - menu::location().x;
175 
176  const std::string icon_img = expanded(*sec) ? open_section_img : closed_section_img;
177  // the "thickness" is the width of the left border
178  int text_start = style_->item_size(indent_list(icon_img, selected_item_.level)).w - style_->get_thickness();
179 
180  // NOTE: if you want to forbid click to the left of the icon
181  // also check x >= text_start-image_width(icon_img)
182  if (menu::double_clicked() || x < text_start) {
183  // Open or close a section if we double-click on it
184  // or do simple click on the icon.
185  expanded(*sec) ? contract(*sec) : expand(*sec);
188  } else if (x >= text_start){
189  // click on title open the topic associated to this section
191  }
192  } else if (selected_item_.t != nullptr) {
193  // Choose a topic if it is clicked.
195  }
196  }
197  return res;
198 }
199 
201 {
202  const topic *ret = chosen_topic_;
203  chosen_topic_ = nullptr;
204  return ret;
205 }
206 
208 {
209  std::vector<std::string> menu_items;
210  for(std::vector<visible_item>::const_iterator items_it = visible_items_.begin(),
211  end = visible_items_.end(); items_it != end; ++items_it) {
212  std::string to_show = items_it->visible_string;
213  if (selected_item_ == *items_it)
214  to_show = std::string("*") + to_show;
215  menu_items.push_back(to_show);
216  }
217  set_items(menu_items, false, true);
218 }
219 
220 help_menu::visible_item::visible_item(const section *_sec, const std::string &vis_string, int lev) :
221  t(nullptr), sec(_sec), visible_string(vis_string), level(lev) {}
222 
223 help_menu::visible_item::visible_item(const topic *_t, const std::string &vis_string, int lev) :
224  t(_t), sec(nullptr), visible_string(vis_string), level(lev) {}
225 
227 {
228  return sec != nullptr && *sec == _sec;
229 }
230 
232 {
233  return t != nullptr && *t == _t;
234 }
235 
237 {
238  return t == vis_item.t && sec == vis_item.sec;
239 }
240 
241 } // end namespace help
void contract(const section &sec)
Contract (close) a section.
Definition: help_menu.cpp:62
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:102
char const IMG_TEXT_SEPARATOR
std::string id
Definition: help_impl.hpp:164
const std::string open_section_img
Definition: help_impl.cpp:85
const std::string topic_img
Definition: help_impl.cpp:83
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:84
A section contains topics and sections along with title and ID.
Definition: help_impl.hpp:146
const std::string menu_expand
Definition: video.hpp:36
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:76
bool expanded(const section &sec)
Return true if the section is expanded.
Definition: help_menu.cpp:50
visible_item(const section *_sec, const std::string &visible_string, int level)
Definition: help_menu.cpp:220
bool is_visible_id(const std::string &id)
Definition: help_impl.cpp:1518
Contains functions for cleanly handling SDL input.
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:188
void display_visible_items()
Draw the currently visible items.
Definition: help_menu.cpp:207
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:92
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:55
help_menu(CVideo &video, const section &toplevel, int max_height=-1)
Definition: help_menu.cpp:34
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:236
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:138
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:1215
uint32_t get_mouse_state(int *x, int *y)
A wrapper for SDL_GetMouseState that gives coordinates in draw space.
Definition: input.cpp:29
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:69
const topic * chosen_topic()
If a topic has been chosen, return that topic, otherwise nullptr.
Definition: help_menu.cpp:200
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:118
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:68