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