The Battle for Wesnoth  1.17.0-dev
help_browser.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_browser.hpp"
17 #include <iostream> // for operator<<, basic_ostream, etc
18 #include <SDL2/SDL_mouse.h> // for SDL_GetMouseState, etc
19 #include "cursor.hpp" // for set, CURSOR_TYPE::HYPERLINK, etc
20 #include "font/constants.hpp" // for relative_size
21 #include "gettext.hpp" // for _
23 #include "help/help_text_area.hpp" // for help_text_area
24 #include "help/help_impl.hpp" // for find_topic, hidden_symbol, etc
25 #include "key.hpp" // for CKey
26 #include "log.hpp" // for log_scope
27 #include "sdl/rect.hpp"
28 
29 class CVideo;
30 struct SDL_Rect;
31 
32 namespace help {
33 
34 help_browser::help_browser(CVideo& video, const section &toplevel) :
35  gui::widget(video),
36  menu_(video,
37  toplevel),
38  text_area_(video, toplevel), toplevel_(toplevel),
39  ref_cursor_(false),
40  back_topics_(),
41  forward_topics_(),
42  back_button_(video, "", gui::button::TYPE_PRESS, "button_normal/button_small_H22", gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_left"),
43  forward_button_(video, "", gui::button::TYPE_PRESS, "button_normal/button_small_H22", gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_right"),
44  shown_topic_(nullptr)
45 {
46  // Hide the buttons at first since we do not have any forward or
47  // back topics at this point. They will be unhidden when history
48  // appears.
49  back_button_.hide(true);
50  forward_button_.hide(true);
51  // Set sizes to some default values.
53 }
54 
56 {
57  const int menu_buttons_padding = font::relative_size(10);
58  const int menu_y = location().y;
59  const int menu_x = location().x;
60  const int menu_w = 250;
61  const int menu_h = height();
62 
63  const int menu_text_area_padding = font::relative_size(10);
64  const int text_area_y = location().y;
65  const int text_area_x = menu_x + menu_w + menu_text_area_padding;
66  const int text_area_w = width() - menu_w - menu_text_area_padding;
67  const int text_area_h = height();
68 
69  const int button_border_padding = 0;
70  const int button_button_padding = font::relative_size(10);
71  const int back_button_x = location().x + button_border_padding;
72  const int back_button_y = menu_y + menu_h + menu_buttons_padding;
73  const int forward_button_x = back_button_x + back_button_.width() + button_button_padding;
74  const int forward_button_y = back_button_y;
75 
76  menu_.set_width(menu_w);
77  menu_.set_location(menu_x, menu_y);
78  menu_.set_max_height(menu_h);
79  menu_.set_max_width(menu_w);
80 
81  text_area_.set_location(text_area_x, text_area_y);
82  text_area_.set_width(text_area_w);
83  text_area_.set_height(text_area_h);
84 
85  back_button_.set_location(back_button_x, back_button_y);
86  forward_button_.set_location(forward_button_x, forward_button_y);
87 
88  set_dirty(true);
89 }
90 
91 void help_browser::update_location(const SDL_Rect&)
92 {
93  adjust_layout();
94 }
95 
97 {
98  CKey key;
99  int mousex, mousey;
100  SDL_GetMouseState(&mousex,&mousey);
101 
102  // Fake focus functionality for the menu, only process it if it has focus.
103  if (sdl::point_in_rect(mousex, mousey, menu_.location())) {
104  menu_.process();
105  const topic *chosen_topic = menu_.chosen_topic();
106  if (chosen_topic != nullptr && chosen_topic != shown_topic_) {
107  // A new topic has been chosen in the menu, display it.
108  show_topic(*chosen_topic);
109  }
110  }
111  if (back_button_.pressed()) {
113  }
114  if (forward_button_.pressed()) {
116  }
117  back_button_.hide(back_topics_.empty());
119 }
120 
121 void help_browser::move_in_history(std::deque<const topic *> &from,
122  std::deque<const topic *> &to)
123 {
124  if (!from.empty()) {
125  const topic *to_show = from.back();
126  from.pop_back();
127  if (shown_topic_ != nullptr) {
128  if (to.size() > max_history) {
129  to.pop_front();
130  }
131  to.push_back(shown_topic_);
132  }
133  show_topic(*to_show, false);
134  }
135 }
136 
137 
138 void help_browser::handle_event(const SDL_Event &event)
139 {
141 
142  SDL_MouseButtonEvent mouse_event = event.button;
143  if (event.type == SDL_MOUSEBUTTONDOWN) {
144  if (mouse_event.button == SDL_BUTTON_LEFT) {
145  // Did the user click a cross-reference?
146  const int mousex = mouse_event.x;
147  const int mousey = mouse_event.y;
148  const std::string ref = text_area_.ref_at(mousex, mousey);
149  if (!ref.empty()) {
150  const topic *t = find_topic(toplevel_, ref);
151  if (t == nullptr) {
152  //
153  // HACK: there are difficult-to-solve issues with a GUI2 popup over the
154  // GUI1 help browser (see issue #2587). Simply disabling it for now.
155  // Should be reenabled once the help browser switches to GUI2.
156  //
157  // -- vultraz, 2018-03-05
158  //
159 #if 0
160  std::stringstream msg;
161  msg << _("Reference to unknown topic: ") << "'" << ref << "'.";
162  gui2::show_transient_message("", msg.str());
163 #endif
164  update_cursor();
165  }
166  else {
167  show_topic(*t);
168  update_cursor();
169  }
170  }
171  }
172  else {
173  const bool mouse_back = !back_button_.hidden() && mouse_event.button == SDL_BUTTON_X1;
174  const bool mouse_forward = !forward_button_.hidden() && mouse_event.button == SDL_BUTTON_X2;
175 
176  if (mouse_back) {
178  }
179  if (mouse_forward) {
181  }
182  if (mouse_back || mouse_forward) {
183  back_button_.hide(back_topics_.empty());
185  }
186  }
187  }
188  else if (event.type == SDL_MOUSEMOTION) {
189  update_cursor();
190  }
191 }
192 
194 {
195  int mousex, mousey;
196  SDL_GetMouseState(&mousex,&mousey);
197  const std::string ref = text_area_.ref_at(mousex, mousey);
198  if (!ref.empty() && !ref_cursor_) {
200  ref_cursor_ = true;
201  }
202  else if (ref.empty() && ref_cursor_) {
204  ref_cursor_ = false;
205  }
206 }
207 
208 void help_browser::show_topic(const std::string &topic_id)
209 {
210  const topic *t = find_topic(toplevel_, topic_id);
211 
212  if (t != nullptr) {
213  show_topic(*t);
214  } else if (topic_id.find(unit_prefix)==0 || topic_id.find(hidden_symbol() + unit_prefix)==0) {
216  } else {
217  std::cerr << "Help browser tried to show topic with id '" << topic_id
218  << "' but that topic could not be found." << std::endl;
219  }
220 }
221 
222 void help_browser::show_topic(const topic &t, bool save_in_history)
223 {
224  log_scope("show_topic");
225 
226  if (save_in_history) {
227  forward_topics_.clear();
228  if (shown_topic_ != nullptr) {
229  if (back_topics_.size() > max_history) {
230  back_topics_.pop_front();
231  }
232  back_topics_.push_back(shown_topic_);
233  }
234  }
235 
236  shown_topic_ = &t;
238  menu_.select_topic(t);
239  update_cursor();
240 }
241 
242 
243 } // end namespace help
void update_cursor()
Update the current cursor, set it to the reference cursor if mousex, mousey is over a cross-reference...
virtual void update_location(const SDL_Rect &rect)
gui::button forward_button_
const std::string unit_prefix
Definition: help_impl.cpp:90
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:176
bool hidden() const
Definition: widget.cpp:188
A section contains topics and sections along with title and ID.
Definition: help_impl.hpp:146
topic const * shown_topic_
const std::string unknown_unit_topic
Definition: help_impl.cpp:89
Definition: video.hpp:32
int relative_size(int size)
Definition: constants.hpp:30
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup, const bool restore_background)
Shows a transient message to the user.
General purpose widgets.
virtual void handle_event(const SDL_Event &event)
void set_width(int w)
Definition: widget.cpp:109
help_browser(CVideo &video, const section &toplevel)
std::deque< const topic * > forward_topics_
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
static std::string _(const char *str)
Definition: gettext.hpp:93
const section & toplevel_
void set_measurements(int w, int h)
Definition: widget.cpp:119
void set_dirty(bool dirty=true)
Definition: widget.cpp:207
virtual void handle_event(const SDL_Event &)
Definition: widget.cpp:330
std::string hidden_symbol(bool hidden)
Definition: help_impl.cpp:1515
std::deque< const topic * > back_topics_
std::string ref_at(const int x, const int y)
Return the ID that is cross-referenced at the (screen) coordinates x, y.
virtual void hide(bool value=true)
Definition: widget.cpp:152
const SDL_Rect & location() const
Definition: widget.cpp:134
gui::button back_button_
void set_max_width(const int new_max_width)
Definition: menu.cpp:428
bool pressed()
Definition: button.cpp:562
virtual void set_location(const SDL_Rect &rect)
Definition: widget.cpp:75
bool point_in_rect(int x, int y, const SDL_Rect &rect)
Tests whether a point is inside a rectangle.
Definition: rect.cpp:23
void move_in_history(std::deque< const topic *> &from, std::deque< const topic *> &to)
Move in the topic history.
void show_topic(const topic &t)
Display the topic.
void show_topic(const std::string &topic_id)
Display the topic with the specified identifier.
virtual void process_event()
#define log_scope(description)
Definition: log.hpp:218
int width() const
Definition: widget.cpp:124
int height() const
Definition: widget.cpp:129
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
const unsigned max_history
Definition: help_impl.cpp:83
Contains the SDL_Rect helper code.
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
Standard logging facilities (interface).
A topic contains a title, an id and some text.
Definition: help_impl.hpp:112
const topic * chosen_topic()
If a topic has been chosen, return that topic, otherwise nullptr.
Definition: help_menu.cpp:199
Definition: help.cpp:57
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:28
void set_height(int h)
Definition: widget.cpp:114
void set_max_height(const int new_max_height)
Set a new max height for this menu.
Definition: menu.cpp:420
help_text_area text_area_