The Battle for Wesnoth  1.17.6+dev
help_browser.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_browser.hpp"
17 #include "cursor.hpp" // for set, CURSOR_TYPE::HYPERLINK, etc
18 #include "font/constants.hpp" // for relative_size
19 #include "gettext.hpp" // for _
21 #include "help/help_text_area.hpp" // for help_text_area
22 #include "help/help_impl.hpp" // for find_topic, hidden_symbol, etc
23 #include "key.hpp" // for CKey
24 #include "log.hpp" // for log_scope
25 #include "sdl/rect.hpp"
26 #include "sdl/input.hpp" // for get_mouse_state
27 
28 struct SDL_Rect;
29 
30 namespace help {
31 
33  gui::widget(),
34  menu_(toplevel),
35  text_area_(toplevel), toplevel_(toplevel),
36  ref_cursor_(false),
37  back_topics_(),
38  forward_topics_(),
39  back_button_("", gui::button::TYPE_PRESS, "button_normal/button_small_H22", gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_left"),
40  forward_button_("", gui::button::TYPE_PRESS, "button_normal/button_small_H22", gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_right"),
41  shown_topic_(nullptr)
42 {
43  // Hide the buttons at first since we do not have any forward or
44  // back topics at this point. They will be unhidden when history
45  // appears.
46  back_button_.hide(true);
47  forward_button_.hide(true);
48  // Set sizes to some default values.
50 }
51 
53 {
54  const int menu_buttons_padding = font::relative_size(10);
55  const int menu_y = location().y;
56  const int menu_x = location().x;
57  const int menu_w = 250;
58  const int menu_h = height();
59 
60  const int menu_text_area_padding = font::relative_size(10);
61  const int text_area_y = location().y;
62  const int text_area_x = menu_x + menu_w + menu_text_area_padding;
63  const int text_area_w = width() - menu_w - menu_text_area_padding;
64  const int text_area_h = height();
65 
66  const int button_border_padding = 0;
67  const int button_button_padding = font::relative_size(10);
68  const int back_button_x = location().x + button_border_padding;
69  const int back_button_y = menu_y + menu_h + menu_buttons_padding;
70  const int forward_button_x = back_button_x + back_button_.width() + button_button_padding;
71  const int forward_button_y = back_button_y;
72 
73  menu_.set_width(menu_w);
74  menu_.set_location(menu_x, menu_y);
75  menu_.set_max_height(menu_h);
76  menu_.set_max_width(menu_w);
77 
78  text_area_.set_location(text_area_x, text_area_y);
79  text_area_.set_width(text_area_w);
80  text_area_.set_height(text_area_h);
81 
82  back_button_.set_location(back_button_x, back_button_y);
83  forward_button_.set_location(forward_button_x, forward_button_y);
84 
85  queue_redraw();
86 }
87 
88 void help_browser::update_location(const SDL_Rect&)
89 {
90  adjust_layout();
91 }
92 
94 {
95  CKey key;
96  int mousex, mousey;
97  sdl::get_mouse_state(&mousex,&mousey);
98 
99  // Fake focus functionality for the menu, only process it if it has focus.
100  if (menu_.location().contains(mousex, mousey)) {
101  menu_.process();
102  const topic *chosen_topic = menu_.chosen_topic();
103  if (chosen_topic != nullptr && chosen_topic != shown_topic_) {
104  // A new topic has been chosen in the menu, display it.
105  show_topic(*chosen_topic);
106  }
107  }
108  if (back_button_.pressed()) {
110  }
111  if (forward_button_.pressed()) {
113  }
114  back_button_.hide(back_topics_.empty());
116 }
117 
118 void help_browser::move_in_history(std::deque<const topic *> &from,
119  std::deque<const topic *> &to)
120 {
121  if (!from.empty()) {
122  const topic *to_show = from.back();
123  from.pop_back();
124  if (shown_topic_ != nullptr) {
125  if (to.size() > max_history) {
126  to.pop_front();
127  }
128  to.push_back(shown_topic_);
129  }
130  show_topic(*to_show, false);
131  }
132 }
133 
134 
135 void help_browser::handle_event(const SDL_Event &event)
136 {
138 
139  SDL_MouseButtonEvent mouse_event = event.button;
140  if (event.type == SDL_MOUSEBUTTONDOWN) {
141  if (mouse_event.button == SDL_BUTTON_LEFT) {
142  // Did the user click a cross-reference?
143  const int mousex = mouse_event.x;
144  const int mousey = mouse_event.y;
145  const std::string ref = text_area_.ref_at(mousex, mousey);
146  if (!ref.empty()) {
147  const topic *t = find_topic(toplevel_, ref);
148  if (t == nullptr) {
149  //
150  // HACK: there are difficult-to-solve issues with a GUI2 popup over the
151  // GUI1 help browser (see issue #2587). Simply disabling it for now.
152  // Should be reenabled once the help browser switches to GUI2.
153  //
154  // -- vultraz, 2018-03-05
155  //
156 #if 0
157  std::stringstream msg;
158  msg << _("Reference to unknown topic: ") << "'" << ref << "'.";
159  gui2::show_transient_message("", msg.str());
160 #endif
161  update_cursor();
162  }
163  else {
164  show_topic(*t);
165  update_cursor();
166  }
167  }
168  }
169  else {
170  const bool mouse_back = !back_button_.hidden() && mouse_event.button == SDL_BUTTON_X1;
171  const bool mouse_forward = !forward_button_.hidden() && mouse_event.button == SDL_BUTTON_X2;
172 
173  if (mouse_back) {
175  }
176  if (mouse_forward) {
178  }
179  if (mouse_back || mouse_forward) {
180  back_button_.hide(back_topics_.empty());
182  }
183  }
184  }
185  else if (event.type == SDL_MOUSEMOTION) {
186  update_cursor();
187  }
188 }
189 
191 {
192  int mousex, mousey;
193  sdl::get_mouse_state(&mousex,&mousey);
194  const std::string ref = text_area_.ref_at(mousex, mousey);
195  if (!ref.empty() && !ref_cursor_) {
197  ref_cursor_ = true;
198  }
199  else if (ref.empty() && ref_cursor_) {
201  ref_cursor_ = false;
202  }
203 }
204 
205 void help_browser::show_topic(const std::string &topic_id)
206 {
207  const topic *t = find_topic(toplevel_, topic_id);
208 
209  if (t != nullptr) {
210  show_topic(*t);
211  } else if (topic_id.find(unit_prefix)==0 || topic_id.find(hidden_symbol() + unit_prefix)==0) {
213  } else {
214  PLAIN_LOG << "Help browser tried to show topic with id '" << topic_id
215  << "' but that topic could not be found." << std::endl;
216  }
217 }
218 
219 void help_browser::show_topic(const topic &t, bool save_in_history)
220 {
221  log_scope("show_topic");
222 
223  if (save_in_history) {
224  forward_topics_.clear();
225  if (shown_topic_ != nullptr) {
226  if (back_topics_.size() > max_history) {
227  back_topics_.pop_front();
228  }
229  back_topics_.push_back(shown_topic_);
230  }
231  }
232 
233  shown_topic_ = &t;
235  menu_.select_topic(t);
236  update_cursor();
237 }
238 
239 
240 } // 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_
#define PLAIN_LOG
Definition: log.hpp:256
const std::string unit_prefix
Definition: help_impl.cpp:88
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:176
bool hidden() const
Definition: widget.cpp:162
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:87
void queue_redraw()
Indicate that the widget should be redrawn.
Definition: widget.cpp:216
int relative_size(int size)
Definition: constants.hpp:30
General purpose widgets.
virtual void handle_event(const SDL_Event &event)
void set_width(int w)
Definition: widget.cpp:99
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
bool contains(int x, int y) const
Whether the given point lies within the rectangle.
Definition: rect.cpp:54
const section & toplevel_
Contains functions for cleanly handling SDL input.
void set_measurements(int w, int h)
Definition: widget.cpp:109
std::string hidden_symbol(bool hidden)
Definition: help_impl.cpp:1512
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:142
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)
Shows a transient message to the user.
gui::button back_button_
const rect & location() const
Definition: widget.cpp:124
void set_max_width(const int new_max_width)
Definition: menu.cpp:430
bool pressed()
Definition: button.cpp:568
virtual void set_location(const SDL_Rect &rect)
Definition: widget.cpp:70
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()
virtual void handle_event(const SDL_Event &) override
Definition: widget.hpp:93
#define log_scope(description)
Definition: log.hpp:235
int width() const
Definition: widget.cpp:114
int height() const
Definition: widget.cpp:119
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
const unsigned max_history
Definition: help_impl.cpp:81
help_browser(const section &toplevel)
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:1213
uint32_t get_mouse_state(int *x, int *y)
A wrapper for SDL_GetMouseState that gives coordinates in draw space.
Definition: input.cpp:27
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:196
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:104
void set_max_height(const int new_max_height)
Set a new max height for this menu.
Definition: menu.cpp:422
help_text_area text_area_