The Battle for Wesnoth  1.19.4+dev
help_browser.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2024
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 "help/help_text_area.hpp" // for help_text_area
20 #include "help/help_impl.hpp" // for find_topic, hidden_symbol, etc
21 #include "key.hpp" // for CKey
22 #include "log.hpp" // for log_scope
23 #include "sdl/rect.hpp"
24 #include "sdl/input.hpp" // for get_mouse_state
25 
26 
27 namespace help {
28 
30  gui::widget(),
31  menu_(toplevel),
32  text_area_(toplevel), toplevel_(toplevel),
33  ref_cursor_(false),
34  back_topics_(),
35  forward_topics_(),
36  back_button_("", gui::button::TYPE_PRESS, "button_normal/button_small_H22", gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_left"),
37  forward_button_("", gui::button::TYPE_PRESS, "button_normal/button_small_H22", gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_right"),
38  shown_topic_(nullptr)
39 {
40  // Hide the buttons at first since we do not have any forward or
41  // back topics at this point. They will be unhidden when history
42  // appears.
43  back_button_.hide(true);
44  forward_button_.hide(true);
45  // Set sizes to some default values.
47 }
48 
50 {
51  const int menu_buttons_padding = font::relative_size(10);
52  const int menu_y = location().y;
53  const int menu_x = location().x;
54  const int menu_w = 250;
55  const int menu_h = height();
56 
57  const int menu_text_area_padding = font::relative_size(10);
58  const int text_area_y = location().y;
59  const int text_area_x = menu_x + menu_w + menu_text_area_padding;
60  const int text_area_w = width() - menu_w - menu_text_area_padding;
61  const int text_area_h = height();
62 
63  const int button_border_padding = 0;
64  const int button_button_padding = font::relative_size(10);
65  const int back_button_x = location().x + button_border_padding;
66  const int back_button_y = menu_y + menu_h + menu_buttons_padding;
67  const int forward_button_x = back_button_x + back_button_.width() + button_button_padding;
68  const int forward_button_y = back_button_y;
69 
70  menu_.set_width(menu_w);
71  menu_.set_location(menu_x, menu_y);
72  menu_.set_max_height(menu_h);
73  menu_.set_max_width(menu_w);
74 
75  text_area_.set_location(text_area_x, text_area_y);
76  text_area_.set_width(text_area_w);
77  text_area_.set_height(text_area_h);
78 
79  back_button_.set_location(back_button_x, back_button_y);
80  forward_button_.set_location(forward_button_x, forward_button_y);
81 
82  queue_redraw();
83 }
84 
85 void help_browser::update_location(const SDL_Rect&)
86 {
87  adjust_layout();
88 }
89 
91 {
92  CKey key;
93  int mousex, mousey;
94  sdl::get_mouse_state(&mousex,&mousey);
95 
96  // Fake focus functionality for the menu, only process it if it has focus.
97  if (menu_.location().contains(mousex, mousey)) {
98  menu_.process();
99  const topic *chosen_topic = menu_.chosen_topic();
100  if (chosen_topic != nullptr && chosen_topic != shown_topic_) {
101  // A new topic has been chosen in the menu, display it.
102  show_topic(*chosen_topic);
103  }
104  }
105  if (back_button_.pressed()) {
107  }
108  if (forward_button_.pressed()) {
110  }
111  back_button_.hide(back_topics_.empty());
113 }
114 
115 void help_browser::move_in_history(std::deque<const topic *> &from,
116  std::deque<const topic *> &to)
117 {
118  if (!from.empty()) {
119  const topic *to_show = from.back();
120  from.pop_back();
121  if (shown_topic_ != nullptr) {
122  if (to.size() > max_history) {
123  to.pop_front();
124  }
125  to.push_back(shown_topic_);
126  }
127  show_topic(*to_show, false);
128  }
129 }
130 
131 
132 void help_browser::handle_event(const SDL_Event &event)
133 {
135 
136  SDL_MouseButtonEvent mouse_event = event.button;
137  if (event.type == SDL_MOUSEBUTTONDOWN) {
138  if (mouse_event.button == SDL_BUTTON_LEFT) {
139  // Did the user click a cross-reference?
140  const int mousex = mouse_event.x;
141  const int mousey = mouse_event.y;
142  const std::string ref = text_area_.ref_at(mousex, mousey);
143  if (!ref.empty()) {
144  const topic *t = find_topic(toplevel_, ref);
145  if (t == nullptr) {
146  //
147  // HACK: there are difficult-to-solve issues with a GUI2 popup over the
148  // GUI1 help browser (see issue #2587). Simply disabling it for now.
149  // Should be reenabled once the help browser switches to GUI2.
150  //
151  // -- vultraz, 2018-03-05
152  //
153 #if 0
154  std::stringstream msg;
155  msg << _("Reference to unknown topic: ") << "'" << ref << "'.";
157 #endif
158  update_cursor();
159  }
160  else {
161  show_topic(*t);
162  update_cursor();
163  }
164  }
165  }
166  else {
167  const bool mouse_back = !back_button_.hidden() && mouse_event.button == SDL_BUTTON_X1;
168  const bool mouse_forward = !forward_button_.hidden() && mouse_event.button == SDL_BUTTON_X2;
169 
170  if (mouse_back) {
172  }
173  if (mouse_forward) {
175  }
176  if (mouse_back || mouse_forward) {
177  back_button_.hide(back_topics_.empty());
179  }
180  }
181  }
182  else if (event.type == SDL_MOUSEMOTION) {
183  update_cursor();
184  }
185 }
186 
188 {
189  int mousex, mousey;
190  sdl::get_mouse_state(&mousex,&mousey);
191  const std::string ref = text_area_.ref_at(mousex, mousey);
192  if (!ref.empty() && !ref_cursor_) {
194  ref_cursor_ = true;
195  }
196  else if (ref.empty() && ref_cursor_) {
198  ref_cursor_ = false;
199  }
200 }
201 
202 void help_browser::show_topic(const std::string &topic_id)
203 {
204  const topic *t = find_topic(toplevel_, topic_id);
205 
206  if (t != nullptr) {
207  show_topic(*t);
208  } else if (topic_id.find(unit_prefix)==0 || topic_id.find(hidden_symbol() + unit_prefix)==0) {
210  } else {
211  PLAIN_LOG << "Help browser tried to show topic with id '" << topic_id
212  << "' but that topic could not be found." << std::endl;
213  }
214 }
215 
216 void help_browser::show_topic(const topic &t, bool save_in_history)
217 {
218  log_scope("show_topic");
219 
220  if (save_in_history) {
221  forward_topics_.clear();
222  if (shown_topic_ != nullptr) {
223  if (back_topics_.size() > max_history) {
224  back_topics_.pop_front();
225  }
226  back_topics_.push_back(shown_topic_);
227  }
228  }
229 
230  shown_topic_ = &t;
233  update_cursor();
234 }
235 
236 
237 } // end namespace help
double t
Definition: astarsearch.cpp:63
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:29
bool pressed()
Definition: button.cpp:567
void set_max_width(const int new_max_width)
Definition: menu.cpp:158
void set_max_height(const int new_max_height)
Set a new max height for this menu.
Definition: menu.cpp:150
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:90
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:104
const topic * chosen_topic()
If a topic has been chosen, return that topic, otherwise nullptr.
Definition: help_menu.cpp:158
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:299
#define log_scope(description)
Definition: log.hpp:278
@ NORMAL
Definition: cursor.hpp:28
@ HYPERLINK
Definition: cursor.hpp:28
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:53
std::string hidden_symbol(bool hidden)
Definition: help_impl.cpp:1626
const std::string unit_prefix
Definition: help_impl.cpp:89
const std::string unknown_unit_topic
Definition: help_impl.cpp:88
const unsigned max_history
Definition: help_impl.cpp:82
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:1298
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:109
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:52