The Battle for Wesnoth  1.17.23+dev
help_browser.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_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 << "'.";
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;
236  update_cursor();
237 }
238 
239 
240 } // end namespace help
double t
Definition: astarsearch.cpp:65
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:29
bool pressed()
Definition: button.cpp:568
void set_max_width(const int new_max_width)
Definition: menu.cpp:406
void set_max_height(const int new_max_height)
Set a new max height for this menu.
Definition: menu.cpp:398
void set_width(int w)
Definition: widget.cpp:98
void set_height(int h)
Definition: widget.cpp:103
virtual void set_location(const SDL_Rect &rect)
Definition: widget.cpp:69
virtual void handle_event(const SDL_Event &) override
Definition: widget.hpp:91
void set_measurements(int w, int h)
Definition: widget.cpp:108
const rect & location() const
Definition: widget.cpp:123
int width() const
Definition: widget.cpp:113
virtual void hide(bool value=true)
Definition: widget.cpp:141
void queue_redraw()
Indicate that the widget should be redrawn.
Definition: widget.cpp:215
int height() const
Definition: widget.cpp:118
bool hidden() const
Definition: widget.cpp:161
void move_in_history(std::deque< const topic * > &from, std::deque< const topic * > &to)
Move in the topic history.
const section & toplevel_
topic const * shown_topic_
void show_topic(const std::string &topic_id)
Display the topic with the specified identifier.
virtual void handle_event(const SDL_Event &event)
help_text_area text_area_
gui::button forward_button_
help_browser(const section &toplevel)
virtual void process_event()
virtual void update_location(const SDL_Rect &rect)
std::deque< const topic * > back_topics_
gui::button back_button_
void update_cursor()
Update the current cursor, set it to the reference cursor if mousex, mousey is over a cross-reference...
std::deque< const topic * > forward_topics_
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 topic * chosen_topic()
If a topic has been chosen, return that topic, otherwise nullptr.
Definition: help_menu.cpp:196
std::string ref_at(const int x, const int y)
Return the ID that is cross-referenced at the (screen) coordinates x, y.
void show_topic(const topic &t)
Display the topic.
static std::string _(const char *str)
Definition: gettext.hpp:93
Contains functions for cleanly handling SDL input.
Standard logging facilities (interface).
#define PLAIN_LOG
Definition: log.hpp:256
#define log_scope(description)
Definition: log.hpp:235
@ NORMAL
Definition: cursor.hpp:29
@ HYPERLINK
Definition: cursor.hpp:29
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:176
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)
Shows a transient message to the user.
General purpose widgets.
Definition: help.cpp:57
std::string hidden_symbol(bool hidden)
Definition: help_impl.cpp:1589
const std::string unit_prefix
Definition: help_impl.cpp:88
const std::string unknown_unit_topic
Definition: help_impl.cpp:87
const unsigned max_history
Definition: help_impl.cpp:81
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
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:110
Contains the SDL_Rect helper code.
This file contains object "key", which is used to store information about keys while annotation parsi...
A section contains topics and sections along with title and ID.
Definition: help_impl.hpp:146
A topic contains a title, an id and some text.
Definition: help_impl.hpp:113
bool contains(int x, int y) const
Whether the given point lies within the rectangle.
Definition: rect.cpp:54