The Battle for Wesnoth  1.15.1+dev
help_browser.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "help/help_browser.hpp"
16 #include <iostream> // for operator<<, basic_ostream, etc
17 #include <SDL2/SDL_mouse.h> // for SDL_GetMouseState, etc
18 #include "cursor.hpp" // for set, CURSOR_TYPE::HYPERLINK, etc
19 #include "font/constants.hpp" // for relative_size
20 #include "gettext.hpp" // for _
22 #include "help/help_text_area.hpp" // for help_text_area
23 #include "help/help_impl.hpp" // for find_topic, hidden_symbol, etc
24 #include "key.hpp" // for CKey
25 #include "log.hpp" // for log_scope
26 #include "sdl/rect.hpp"
27 
28 class CVideo;
29 struct SDL_Rect;
30 
31 namespace help {
32 
33 help_browser::help_browser(CVideo& video, const section &toplevel) :
34  gui::widget(video),
35  menu_(video,
36  toplevel),
37  text_area_(video, toplevel), toplevel_(toplevel),
38  ref_cursor_(false),
39  back_topics_(),
40  forward_topics_(),
41  back_button_(video, "", gui::button::TYPE_PRESS, "button_normal/button_small_H22", gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_left"),
42  forward_button_(video, "", gui::button::TYPE_PRESS, "button_normal/button_small_H22", gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_right"),
43  shown_topic_(nullptr)
44 {
45  // Hide the buttons at first since we do not have any forward or
46  // back topics at this point. They will be unhidden when history
47  // appears.
48  back_button_.hide(true);
49  forward_button_.hide(true);
50  // Set sizes to some default values.
52 }
53 
55 {
56  const int menu_buttons_padding = font::relative_size(10);
57  const int menu_y = location().y;
58  const int menu_x = location().x;
59  const int menu_w = 250;
60  const int menu_h = height();
61 
62  const int menu_text_area_padding = font::relative_size(10);
63  const int text_area_y = location().y;
64  const int text_area_x = menu_x + menu_w + menu_text_area_padding;
65  const int text_area_w = width() - menu_w - menu_text_area_padding;
66  const int text_area_h = height();
67 
68  const int button_border_padding = 0;
69  const int button_button_padding = font::relative_size(10);
70  const int back_button_x = location().x + button_border_padding;
71  const int back_button_y = menu_y + menu_h + menu_buttons_padding;
72  const int forward_button_x = back_button_x + back_button_.width() + button_button_padding;
73  const int forward_button_y = back_button_y;
74 
75  menu_.set_width(menu_w);
76  menu_.set_location(menu_x, menu_y);
77  menu_.set_max_height(menu_h);
78  menu_.set_max_width(menu_w);
79 
80  text_area_.set_location(text_area_x, text_area_y);
81  text_area_.set_width(text_area_w);
82  text_area_.set_height(text_area_h);
83 
84  back_button_.set_location(back_button_x, back_button_y);
85  forward_button_.set_location(forward_button_x, forward_button_y);
86 
87  set_dirty(true);
88 }
89 
90 void help_browser::update_location(const SDL_Rect&)
91 {
92  adjust_layout();
93 }
94 
96 {
97  CKey key;
98  int mousex, mousey;
99  SDL_GetMouseState(&mousex,&mousey);
100 
101  /// Fake focus functionality for the menu, only process it if it has focus.
102  if (sdl::point_in_rect(mousex, mousey, menu_.location())) {
103  menu_.process();
104  const topic *chosen_topic = menu_.chosen_topic();
105  if (chosen_topic != nullptr && chosen_topic != shown_topic_) {
106  /// A new topic has been chosen in the menu, display it.
107  show_topic(*chosen_topic);
108  }
109  }
110  if (back_button_.pressed()) {
112  }
113  if (forward_button_.pressed()) {
115  }
116  back_button_.hide(back_topics_.empty());
118 }
119 
120 void help_browser::move_in_history(std::deque<const topic *> &from,
121  std::deque<const topic *> &to)
122 {
123  if (!from.empty()) {
124  const topic *to_show = from.back();
125  from.pop_back();
126  if (shown_topic_ != nullptr) {
127  if (to.size() > max_history) {
128  to.pop_front();
129  }
130  to.push_back(shown_topic_);
131  }
132  show_topic(*to_show, false);
133  }
134 }
135 
136 
137 void help_browser::handle_event(const SDL_Event &event)
138 {
140 
141  SDL_MouseButtonEvent mouse_event = event.button;
142  if (event.type == SDL_MOUSEBUTTONDOWN) {
143  if (mouse_event.button == SDL_BUTTON_LEFT) {
144  // Did the user click a cross-reference?
145  const int mousex = mouse_event.x;
146  const int mousey = mouse_event.y;
147  const std::string ref = text_area_.ref_at(mousex, mousey);
148  if (!ref.empty()) {
149  const topic *t = find_topic(toplevel_, ref);
150  if (t == nullptr) {
151  //
152  // HACK: there are difficult-to-solve issues with a GUI2 popup over the
153  // GUI1 help browser (see issue #2587). Simply disabling it for now.
154  // Should be reenabled once the help browser switches to GUI2.
155  //
156  // -- vultraz, 2018-03-05
157  //
158 #if 0
159  std::stringstream msg;
160  msg << _("Reference to unknown topic: ") << "'" << ref << "'.";
161  gui2::show_transient_message("", msg.str());
162 #endif
163  update_cursor();
164  }
165  else {
166  show_topic(*t);
167  update_cursor();
168  }
169  }
170  }
171  else {
172  const bool mouse_back = !back_button_.hidden() && mouse_event.button == SDL_BUTTON_X1;
173  const bool mouse_forward = !forward_button_.hidden() && mouse_event.button == SDL_BUTTON_X2;
174 
175  if (mouse_back) {
177  }
178  if (mouse_forward) {
180  }
181  if (mouse_back || mouse_forward) {
182  back_button_.hide(back_topics_.empty());
184  }
185  }
186  }
187  else if (event.type == SDL_MOUSEMOTION) {
188  update_cursor();
189  }
190 }
191 
193 {
194  int mousex, mousey;
195  SDL_GetMouseState(&mousex,&mousey);
196  const std::string ref = text_area_.ref_at(mousex, mousey);
197  if (!ref.empty() && !ref_cursor_) {
199  ref_cursor_ = true;
200  }
201  else if (ref.empty() && ref_cursor_) {
203  ref_cursor_ = false;
204  }
205 }
206 
207 void help_browser::show_topic(const std::string &topic_id)
208 {
209  const topic *t = find_topic(toplevel_, topic_id);
210 
211  if (t != nullptr) {
212  show_topic(*t);
213  } else if (topic_id.find(unit_prefix)==0 || topic_id.find(hidden_symbol() + unit_prefix)==0) {
215  } else {
216  std::cerr << "Help browser tried to show topic with id '" << topic_id
217  << "' but that topic could not be found." << std::endl;
218  }
219 }
220 
221 void help_browser::show_topic(const topic &t, bool save_in_history)
222 {
223  log_scope("show_topic");
224 
225  if (save_in_history) {
226  forward_topics_.clear();
227  if (shown_topic_ != nullptr) {
228  if (back_topics_.size() > max_history) {
229  back_topics_.pop_front();
230  }
231  back_topics_.push_back(shown_topic_);
232  }
233  }
234 
235  shown_topic_ = &t;
237  menu_.select_topic(t);
238  update_cursor();
239 }
240 
241 
242 } // 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:89
void set(CURSOR_TYPE type)
Use the default parameter to reset cursors.
Definition: cursor.cpp:173
bool hidden() const
Definition: widget.cpp:188
A section contains topics and sections along with title and ID.
Definition: help_impl.hpp:141
topic const * shown_topic_
const std::string unknown_unit_topic
Definition: help_impl.cpp:88
Definition: video.hpp:31
int relative_size(int size)
Definition: constants.hpp:29
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:109
const section & toplevel_
void set_measurements(int w, int h)
Definition: widget.cpp:119
void set_dirty(bool dirty=true)
Definition: widget.cpp:207
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
virtual void handle_event(const SDL_Event &)
Definition: widget.cpp:330
std::string hidden_symbol(bool hidden)
Definition: help_impl.cpp:1391
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:475
bool pressed()
Definition: button.cpp:580
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:22
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:186
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:82
Contains the SDL_Rect helper code.
double t
Definition: astarsearch.cpp:64
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:1094
Standard logging facilities (interface).
A topic contains a title, an id and some text.
Definition: help_impl.hpp:107
const topic * chosen_topic()
If a topic has been chosen, return that topic, otherwise nullptr.
Definition: help_menu.cpp:195
Definition: help.cpp:56
Class that keeps track of all the keys on the keyboard.
Definition: key.hpp:27
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:467
help_text_area text_area_