Removed GUI1 Help interface code

Not needed anymore since we're moving to GUI2 for this dialog.
This commit is contained in:
Charles Dang 2018-03-20 19:21:33 +11:00 committed by Celtic Minstrel
parent e6c0064755
commit 03e11a62e1
9 changed files with 0 additions and 1414 deletions

View File

@ -277,12 +277,6 @@
46F57088205FCF7E007031BF /* config_attribute_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC0341DF1ECF46FE000F2E2B /* config_attribute_value.cpp */; };
46F92C142174F5D700602C1C /* help_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46F92C0A2174F5D600602C1C /* help_impl.cpp */; };
46F92C152174F5D700602C1C /* help_impl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46F92C0A2174F5D600602C1C /* help_impl.cpp */; };
46F92C162174F5D700602C1C /* help_browser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46F92C0B2174F5D600602C1C /* help_browser.cpp */; };
46F92C172174F5D700602C1C /* help_browser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46F92C0B2174F5D600602C1C /* help_browser.cpp */; };
46F92C182174F5D700602C1C /* help_menu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46F92C0F2174F5D700602C1C /* help_menu.cpp */; };
46F92C192174F5D700602C1C /* help_menu.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46F92C0F2174F5D700602C1C /* help_menu.cpp */; };
46F92C1A2174F5D700602C1C /* help_text_area.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46F92C102174F5D700602C1C /* help_text_area.cpp */; };
46F92C1B2174F5D700602C1C /* help_text_area.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46F92C102174F5D700602C1C /* help_text_area.cpp */; };
46F92C1C2174F5D700602C1C /* help_topic_generators.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46F92C112174F5D700602C1C /* help_topic_generators.cpp */; };
46F92C1D2174F5D700602C1C /* help_topic_generators.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46F92C112174F5D700602C1C /* help_topic_generators.cpp */; };
46F92C1E2174F5D700602C1C /* help.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 46F92C132174F5D700602C1C /* help.cpp */; };
@ -1780,14 +1774,8 @@
46F54C26211DFB7200374A1C /* apple_version.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = apple_version.mm; path = ../../src/desktop/apple_version.mm; sourceTree = "<group>"; };
46F54C28211DFB9100374A1C /* apple_version.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = apple_version.hpp; path = ../../src/desktop/apple_version.hpp; sourceTree = "<group>"; };
46F92C082174F5D600602C1C /* help.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = help.hpp; sourceTree = "<group>"; };
46F92C092174F5D600602C1C /* help_browser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = help_browser.hpp; sourceTree = "<group>"; };
46F92C0A2174F5D600602C1C /* help_impl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = help_impl.cpp; sourceTree = "<group>"; };
46F92C0B2174F5D600602C1C /* help_browser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = help_browser.cpp; sourceTree = "<group>"; };
46F92C0C2174F5D700602C1C /* help_impl.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = help_impl.hpp; sourceTree = "<group>"; };
46F92C0D2174F5D700602C1C /* help_menu.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = help_menu.hpp; sourceTree = "<group>"; };
46F92C0E2174F5D700602C1C /* help_text_area.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = help_text_area.hpp; sourceTree = "<group>"; };
46F92C0F2174F5D700602C1C /* help_menu.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = help_menu.cpp; sourceTree = "<group>"; };
46F92C102174F5D700602C1C /* help_text_area.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = help_text_area.cpp; sourceTree = "<group>"; };
46F92C112174F5D700602C1C /* help_topic_generators.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = help_topic_generators.cpp; sourceTree = "<group>"; };
46F92C122174F5D700602C1C /* help_topic_generators.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = help_topic_generators.hpp; sourceTree = "<group>"; };
46F92C132174F5D700602C1C /* help.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = help.cpp; sourceTree = "<group>"; };
@ -4406,14 +4394,8 @@
91B6218E1B76710700B00E0F /* help */ = {
isa = PBXGroup;
children = (
46F92C0B2174F5D600602C1C /* help_browser.cpp */,
46F92C092174F5D600602C1C /* help_browser.hpp */,
46F92C0A2174F5D600602C1C /* help_impl.cpp */,
46F92C0C2174F5D700602C1C /* help_impl.hpp */,
46F92C0F2174F5D700602C1C /* help_menu.cpp */,
46F92C0D2174F5D700602C1C /* help_menu.hpp */,
46F92C102174F5D700602C1C /* help_text_area.cpp */,
46F92C0E2174F5D700602C1C /* help_text_area.hpp */,
46F92C112174F5D700602C1C /* help_topic_generators.cpp */,
46F92C122174F5D700602C1C /* help_topic_generators.hpp */,
46F92C132174F5D700602C1C /* help.cpp */,
@ -5549,7 +5531,6 @@
B5599B7E0EC62181008DD061 /* color_range.cpp in Sources */,
ECFA82E3184E59F3006782FB /* command_executor.cpp in Sources */,
46F92E692174F6A400602C1C /* tree_view_node.cpp in Sources */,
46F92C162174F5D700602C1C /* help_browser.cpp in Sources */,
F46C5DCF13A5074C00DD0816 /* commandline_options.cpp in Sources */,
46F92DC92174F6A300602C1C /* modal_dialog.cpp in Sources */,
46F92D932174F6A300602C1C /* distributor.cpp in Sources */,
@ -5867,7 +5848,6 @@
EC64D7611A085CE60092EF75 /* seed_rng.cpp in Sources */,
B5599B030EC62181008DD061 /* map_settings.cpp in Sources */,
91AF565B284D9251007A7652 /* walker_scrollbar_container.cpp in Sources */,
46F92C1A2174F5D700602C1C /* help_text_area.cpp in Sources */,
46F92DC12174F6A300602C1C /* game_version_dialog.cpp in Sources */,
ECAB84551B0C1934001A3EB7 /* shroud_clearing_action.cpp in Sources */,
46F92E892174F6A400602C1C /* matrix.cpp in Sources */,
@ -6015,7 +5995,6 @@
9193FC7E1D5BB64F004F6C07 /* advancement.cpp in Sources */,
9193FC821D5C2CF8004F6C07 /* lua_unit.cpp in Sources */,
9193FC861D5D7461004F6C07 /* lua_unit_attacks.cpp in Sources */,
46F92C182174F5D700602C1C /* help_menu.cpp in Sources */,
46F92E292174F6A400602C1C /* mp_join_game.cpp in Sources */,
46F92E592174F6A400602C1C /* image.cpp in Sources */,
469853CF24D3560900B0E93B /* server_info_dialog.cpp in Sources */,
@ -6351,7 +6330,6 @@
46D60159255AFA7E00E072F0 /* commandline_argv.cpp in Sources */,
46F92F202174FEC000602C1C /* constants.cpp in Sources */,
91E356C31CACC8B800774252 /* candidates.cpp in Sources */,
46F92C192174F5D700602C1C /* help_menu.cpp in Sources */,
91E356C41CACC8B800774252 /* engine_fai.cpp in Sources */,
91E356C51CACC8B800774252 /* function_table.cpp in Sources */,
91E356C61CACC8B800774252 /* stage_side_formulas.cpp in Sources */,
@ -6653,7 +6631,6 @@
461DC52E241F875A00B9DD10 /* lua_color.cpp in Sources */,
91A215BB1CAD92D000927AEA /* tstring.cpp in Sources */,
91A215BF1CAD951A00927AEA /* lua_jailbreak_exception.cpp in Sources */,
46F92C1B2174F5D700602C1C /* help_text_area.cpp in Sources */,
91A215C01CAD952C00927AEA /* game_config.cpp in Sources */,
91A215C11CAD952C00927AEA /* game_config_manager.cpp in Sources */,
91A215C21CAD954C00927AEA /* filesystem.cpp in Sources */,
@ -6701,7 +6678,6 @@
46F92E462174F6A400602C1C /* tips.cpp in Sources */,
9107AE461DB335D5001927B0 /* paths.cpp in Sources */,
46F92DAC2174F6A300602C1C /* unit_recall.cpp in Sources */,
46F92C172174F5D700602C1C /* help_browser.cpp in Sources */,
915C68EC1DF1DCB000594B07 /* color.cpp in Sources */,
4291489DA38012477DA3BA7C /* general.cpp in Sources */,
87744447951D17AA38BE5F48 /* mp_report.cpp in Sources */,

View File

@ -286,10 +286,7 @@ gui/widgets/widget.cpp
gui/widgets/widget_helpers.cpp
halo.cpp
help/help.cpp
help/help_browser.cpp
help/help_impl.cpp
help/help_menu.cpp
help/help_text_area.cpp
help/help_topic_generators.cpp
hotkey/hotkey_handler.cpp
hotkey/hotkey_handler_mp.cpp

View File

@ -30,7 +30,6 @@
#include "gettext.hpp" // for _
#include "gui/dialogs/help_browser.hpp"
#include "gui/widgets/settings.hpp"
#include "help/help_browser.hpp" // for help_browser
#include "help/help_impl.hpp" // for hidden_symbol, toplevel, etc
#include "key.hpp" // for CKey
#include "log.hpp" // for LOG_STREAM, log_domain

View File

@ -1,237 +0,0 @@
/*
Copyright (C) 2003 - 2024
by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "help/help_browser.hpp"
#include "cursor.hpp" // for set, CURSOR_TYPE::HYPERLINK, etc
#include "font/constants.hpp" // for relative_size
#include "help/help_text_area.hpp" // for help_text_area
#include "help/help_impl.hpp" // for find_topic, hidden_symbol, etc
#include "key.hpp" // for CKey
#include "log.hpp" // for log_scope
#include "sdl/rect.hpp"
#include "sdl/input.hpp" // for get_mouse_state
namespace help {
help_browser::help_browser(const section &toplevel) :
gui::widget(),
menu_(toplevel),
text_area_(toplevel), toplevel_(toplevel),
ref_cursor_(false),
back_topics_(),
forward_topics_(),
back_button_("", gui::button::TYPE_PRESS, "button_normal/button_small_H22", gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_left"),
forward_button_("", gui::button::TYPE_PRESS, "button_normal/button_small_H22", gui::button::DEFAULT_SPACE, true, "icons/arrows/long_arrow_ornate_right"),
shown_topic_(nullptr)
{
// Hide the buttons at first since we do not have any forward or
// back topics at this point. They will be unhidden when history
// appears.
back_button_.hide(true);
forward_button_.hide(true);
// Set sizes to some default values.
set_measurements(font::relative_size(400), font::relative_size(500));
}
void help_browser::adjust_layout()
{
const int menu_buttons_padding = font::relative_size(10);
const int menu_y = location().y;
const int menu_x = location().x;
const int menu_w = 250;
const int menu_h = height();
const int menu_text_area_padding = font::relative_size(10);
const int text_area_y = location().y;
const int text_area_x = menu_x + menu_w + menu_text_area_padding;
const int text_area_w = width() - menu_w - menu_text_area_padding;
const int text_area_h = height();
const int button_border_padding = 0;
const int button_button_padding = font::relative_size(10);
const int back_button_x = location().x + button_border_padding;
const int back_button_y = menu_y + menu_h + menu_buttons_padding;
const int forward_button_x = back_button_x + back_button_.width() + button_button_padding;
const int forward_button_y = back_button_y;
menu_.set_width(menu_w);
menu_.set_location(menu_x, menu_y);
menu_.set_max_height(menu_h);
menu_.set_max_width(menu_w);
text_area_.set_location(text_area_x, text_area_y);
text_area_.set_width(text_area_w);
text_area_.set_height(text_area_h);
back_button_.set_location(back_button_x, back_button_y);
forward_button_.set_location(forward_button_x, forward_button_y);
queue_redraw();
}
void help_browser::update_location(const SDL_Rect&)
{
adjust_layout();
}
void help_browser::process_event()
{
CKey key;
int mousex, mousey;
sdl::get_mouse_state(&mousex,&mousey);
// Fake focus functionality for the menu, only process it if it has focus.
if (menu_.location().contains(mousex, mousey)) {
menu_.process();
const topic *chosen_topic = menu_.chosen_topic();
if (chosen_topic != nullptr && chosen_topic != shown_topic_) {
// A new topic has been chosen in the menu, display it.
show_topic(*chosen_topic);
}
}
if (back_button_.pressed()) {
move_in_history(back_topics_, forward_topics_);
}
if (forward_button_.pressed()) {
move_in_history(forward_topics_, back_topics_);
}
back_button_.hide(back_topics_.empty());
forward_button_.hide(forward_topics_.empty());
}
void help_browser::move_in_history(std::deque<const topic *> &from,
std::deque<const topic *> &to)
{
if (!from.empty()) {
const topic *to_show = from.back();
from.pop_back();
if (shown_topic_ != nullptr) {
if (to.size() > max_history) {
to.pop_front();
}
to.push_back(shown_topic_);
}
show_topic(*to_show, false);
}
}
void help_browser::handle_event(const SDL_Event &event)
{
gui::widget::handle_event(event);
SDL_MouseButtonEvent mouse_event = event.button;
if (event.type == SDL_MOUSEBUTTONDOWN) {
if (mouse_event.button == SDL_BUTTON_LEFT) {
// Did the user click a cross-reference?
const int mousex = mouse_event.x;
const int mousey = mouse_event.y;
const std::string ref = text_area_.ref_at(mousex, mousey);
if (!ref.empty()) {
const topic *t = find_topic(toplevel_, ref);
if (t == nullptr) {
//
// HACK: there are difficult-to-solve issues with a GUI2 popup over the
// GUI1 help browser (see issue #2587). Simply disabling it for now.
// Should be reenabled once the help browser switches to GUI2.
//
// -- vultraz, 2018-03-05
//
#if 0
std::stringstream msg;
msg << _("Reference to unknown topic: ") << "'" << ref << "'.";
gui2::show_transient_message("", msg.str());
#endif
update_cursor();
}
else {
show_topic(*t);
update_cursor();
}
}
}
else {
const bool mouse_back = !back_button_.hidden() && mouse_event.button == SDL_BUTTON_X1;
const bool mouse_forward = !forward_button_.hidden() && mouse_event.button == SDL_BUTTON_X2;
if (mouse_back) {
move_in_history(back_topics_, forward_topics_);
}
if (mouse_forward) {
move_in_history(forward_topics_, back_topics_);
}
if (mouse_back || mouse_forward) {
back_button_.hide(back_topics_.empty());
forward_button_.hide(forward_topics_.empty());
}
}
}
else if (event.type == SDL_MOUSEMOTION) {
update_cursor();
}
}
void help_browser::update_cursor()
{
int mousex, mousey;
sdl::get_mouse_state(&mousex,&mousey);
const std::string ref = text_area_.ref_at(mousex, mousey);
if (!ref.empty() && !ref_cursor_) {
cursor::set(cursor::HYPERLINK);
ref_cursor_ = true;
}
else if (ref.empty() && ref_cursor_) {
cursor::set(cursor::NORMAL);
ref_cursor_ = false;
}
}
void help_browser::show_topic(const std::string &topic_id)
{
const topic *t = find_topic(toplevel_, topic_id);
if (t != nullptr) {
show_topic(*t);
} else if (topic_id.find(unit_prefix)==0 || topic_id.find(hidden_symbol() + unit_prefix)==0) {
show_topic(unknown_unit_topic);
} else {
PLAIN_LOG << "Help browser tried to show topic with id '" << topic_id
<< "' but that topic could not be found." << std::endl;
}
}
void help_browser::show_topic(const topic &t, bool save_in_history)
{
log_scope("show_topic");
if (save_in_history) {
forward_topics_.clear();
if (shown_topic_ != nullptr) {
if (back_topics_.size() > max_history) {
back_topics_.pop_front();
}
back_topics_.push_back(shown_topic_);
}
}
shown_topic_ = &t;
text_area_.show_topic(t);
menu_.select_topic(t);
update_cursor();
}
} // end namespace help

View File

@ -1,71 +0,0 @@
/*
Copyright (C) 2003 - 2024
by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#pragma once
#include <deque> // for deque
#include <string> // for string
#include <SDL2/SDL_events.h> // for SDL_Event
#include "help_menu.hpp" // for help_menu
#include "help_text_area.hpp" // for help_text_area
#include "widgets/button.hpp" // for button
#include "widgets/widget.hpp" // for widget
namespace help {
/** A help browser widget. */
class help_browser : public gui::widget
{
public:
help_browser(const section &toplevel);
void adjust_layout();
/**
* Display the topic with the specified identifier. Open the menu
* on the right location and display the topic in the text area.
*/
void show_topic(const std::string &topic_id);
protected:
virtual void update_location(const SDL_Rect& rect);
virtual void process_event();
virtual void handle_event(const SDL_Event &event);
private:
/**
* Update the current cursor, set it to the reference cursor if
* mousex, mousey is over a cross-reference, otherwise, set it to
* the normal cursor.
*/
void update_cursor();
void show_topic(const topic &t, bool save_in_history=true);
/**
* Move in the topic history. Pop an element from from and insert
* it in to. Pop at the fronts if the maximum number of elements is
* exceeded.
*/
void move_in_history(std::deque<const topic *> &from, std::deque<const topic *> &to);
help_menu menu_;
help_text_area text_area_;
const section &toplevel_;
bool ref_cursor_; // If the cursor currently is the hyperlink cursor.
std::deque<const topic *> back_topics_, forward_topics_;
gui::button back_button_, forward_button_;
topic const *shown_topic_;
};
} // end namespace help

View File

@ -1,210 +0,0 @@
/*
Copyright (C) 2003 - 2024
by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "help/help_menu.hpp"
#include "game_config.hpp" // for menu_contract, menu_expand
#include "help/help_impl.hpp" // for section, topic, topic_list, etc
#include "sound.hpp" // for play_UI_sound
#include "sdl/input.hpp" // for get_mouse_state
#include <algorithm> // for find
#include <list> // for _List_const_iterator, etc
#include <utility> // for pair
namespace help {
help_menu::help_menu(const section& toplevel, int max_height) :
gui::menu(true, max_height, -1, &gui::menu::bluebg_style),
visible_items_(),
toplevel_(toplevel),
expanded_(),
chosen_topic_(nullptr),
selected_item_(&toplevel, 0)
{
silent_ = true; //silence the default menu sounds
update_visible_items(toplevel_);
display_visible_items();
if (!visible_items_.empty())
selected_item_ = visible_items_.front();
}
bool help_menu::expanded(const section &sec) const
{
return expanded_.find(&sec) != expanded_.end();
}
void help_menu::expand(const section &sec)
{
if (sec.id != "toplevel" && expanded_.insert(&sec).second) {
sound::play_UI_sound(game_config::sounds::menu_expand);
}
}
void help_menu::contract(const section &sec)
{
if (expanded_.erase(&sec)) {
sound::play_UI_sound(game_config::sounds::menu_contract);
}
}
void help_menu::update_visible_items(const section &sec, unsigned level)
{
if (level == 0) {
// Clear if this is the top level, otherwise append items.
visible_items_.clear();
}
for (const auto &s : sec.sections) {
if (is_visible_id(s.id)) {
visible_items_.emplace_back(&s, level + 1);
if (expanded(s)) {
update_visible_items(s, level + 1);
}
}
}
for (const auto &t : sec.topics) {
if (is_visible_id(t.id)) {
visible_items_.emplace_back(&t, level + 1);
}
}
}
bool help_menu::select_topic_internal(const topic &t, const section &sec)
{
topic_list::const_iterator tit =
std::find(sec.topics.begin(), sec.topics.end(), t);
if (tit != sec.topics.end()) {
// topic starting with ".." are assumed as rooted in the parent section
// and so only expand the parent when selected
if (t.id.size()<2 || t.id[0] != '.' || t.id[1] != '.')
expand(sec);
return true;
}
for (const auto &s : sec.sections) {
if (select_topic_internal(t, s)) {
expand(sec);
return true;
}
}
return false;
}
void help_menu::select_topic(const topic &t)
{
if (selected_item_ == t) {
// The requested topic is already selected.
return;
}
if (select_topic_internal(t, toplevel_)) {
update_visible_items(toplevel_);
for (std::vector<visible_item>::const_iterator it = visible_items_.begin();
it != visible_items_.end(); ++it) {
if (*it == t) {
selected_item_ = *it;
break;
}
}
display_visible_items();
}
}
int help_menu::process()
{
int res = menu::process();
int mousex, mousey;
sdl::get_mouse_state(&mousex, &mousey);
if (!visible_items_.empty()
&& static_cast<std::size_t>(res) < visible_items_.size())
{
selected_item_ = visible_items_[res];
const section* sec = selected_item_.sec;
if (sec != nullptr) {
// Behavior of the UI, for section headings:
// * user single-clicks on the text part: show the ".." topic in the right-hand pane
// * user single-clicks on the icon (or to the left of it): expand or collapse the tree view
// * user double-clicks anywhere: expand or collapse the tree view
// * note: the first click of the double-click has the single-click effect too
if (menu::double_clicked() || hit_on_indent_or_icon(static_cast<std::size_t>(res), mousex)) {
// Open or close a section if we double-click on it
// or do simple click on the icon.
expanded(*sec) ? contract(*sec) : expand(*sec);
update_visible_items(toplevel_);
display_visible_items();
} else {
// click on title open the topic associated to this section
chosen_topic_ = find_topic(default_toplevel, ".."+sec->id );
}
} else if (selected_item_.t != nullptr) {
// Choose a topic if it is clicked.
chosen_topic_ = selected_item_.t;
}
}
return res;
}
const topic *help_menu::chosen_topic()
{
const topic *ret = chosen_topic_;
chosen_topic_ = nullptr;
return ret;
}
void help_menu::display_visible_items()
{
std::vector<gui::indented_menu_item> menu_items;
utils::optional<std::size_t> selected;
for(std::vector<visible_item>::const_iterator items_it = visible_items_.begin(),
end = visible_items_.end(); items_it != end; ++items_it) {
if (selected_item_ == *items_it)
selected = menu_items.size();
menu_items.push_back(items_it->get_menu_item(*this));
}
set_items(menu_items, selected);
}
help_menu::visible_item::visible_item(const section *_sec, int lev) :
t(nullptr), sec(_sec), level(lev) {}
help_menu::visible_item::visible_item(const topic *_t, int lev) :
t(_t), sec(nullptr), level(lev) {}
gui::indented_menu_item help_menu::visible_item::get_menu_item(const help_menu& parent) const
{
if(sec) {
const auto& img = parent.expanded(*sec) ? open_section_img : closed_section_img;
return {level, img, sec->title};
}
// As sec was a nullptr, this must have a non-null topic
return {level, topic_img, t->title};
}
bool help_menu::visible_item::operator==(const section &_sec) const
{
return sec != nullptr && *sec == _sec;
}
bool help_menu::visible_item::operator==(const topic &_t) const
{
return t != nullptr && *t == _t;
}
bool help_menu::visible_item::operator==(const visible_item &vis_item) const
{
return t == vis_item.t && sec == vis_item.sec;
}
} // end namespace help

View File

@ -1,109 +0,0 @@
/*
Copyright (C) 2003 - 2024
by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#pragma once
#include <set> // for set
#include <string> // for string, basic_string
#include <vector> // for vector
#include "widgets/menu.hpp" // for menu
namespace help { struct section; }
namespace help { struct topic; }
namespace help {
/**
* The menu to the left in the help browser, where topics can be
* navigated through and chosen.
*/
class help_menu : public gui::menu
{
public:
help_menu(const section &toplevel, int max_height=-1);
int process();
/**
* Make the topic the currently selected one, and expand all
* sections that need to be expanded to show it.
*/
void select_topic(const topic &t);
/**
* If a topic has been chosen, return that topic, otherwise
* nullptr. If one topic is returned, it will not be returned again,
* if it is not re-chosen.
*/
const topic *chosen_topic();
private:
/** Information about an item that is visible in the menu. */
struct visible_item {
visible_item(const section *_sec, int level);
visible_item(const topic *_t, int level);
// Invariant, one if these should be nullptr. The constructors
// enforce it.
const topic *t;
const section *sec;
gui::indented_menu_item get_menu_item(const help_menu& parent) const;
/** Indentation level, always one more than the parent section. */
int level;
bool operator==(const visible_item &sec) const;
bool operator==(const section &sec) const;
bool operator==(const topic &t) const;
};
/** Regenerate what items are visible by checking what sections are expanded. */
void update_visible_items(const section &top_level, unsigned starting_level=0);
/** Return true if the section is expanded. */
bool expanded(const section &sec) const;
/** Mark a section as expanded. Do not update the visible items or anything. */
void expand(const section &sec);
/**
* Contract (close) a section. That is, mark it as not expanded,
* visible items are not updated.
*/
void contract(const section &sec);
/**
* Return the string to use as the prefix for the icon part of the
* menu-string at the specified level.
*/
std::string indent_list(const std::string &icon, const unsigned level);
/** Return the data to use with the superclass's set_items() for sections at the specified level. */
gui::indented_menu_item get_item_to_show(const section &sec, const unsigned level);
/** Return the data to use with the superclass's set_items() for topics at the specified level. */
gui::indented_menu_item get_item_to_show(const topic &topic, const unsigned level);
/** Draw the currently visible items. */
void display_visible_items();
/**
* Internal recursive thingie. did_expand will be true if any
* section was expanded, otherwise untouched.
*/
bool select_topic_internal(const topic &t, const section &sec);
std::vector<visible_item> visible_items_;
const section &toplevel_;
std::set<const section*> expanded_;
topic const *chosen_topic_;
visible_item selected_item_;
};
} // end namespace help

View File

@ -1,582 +0,0 @@
/*
Copyright (C) 2003 - 2024
by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "help/help_text_area.hpp"
#include "config.hpp" // for config, etc
#include "draw.hpp" // for blit, fill
#include "font/sdl_ttf_compat.hpp"
#include "font/standard_colors.hpp" // for string_to_color
#include "game_config.hpp" // for debug
#include "help/help_impl.hpp" // for parse_error, box_width, etc
#include "lexical_cast.hpp"
#include "log.hpp" // for LOG_STREAM, log_domain, etc
#include "picture.hpp" // for get_image
#include "preferences/preferences.hpp" // for font_scaled
#include "sdl/rect.hpp" // for draw_rectangle, etc
#include "sdl/texture.hpp" // for texture
#include "serialization/parser.hpp" // for read, write
#include <algorithm> // for max, min, find_if
#include <vector> // for vector, etc
static lg::log_domain log_display("display");
#define WRN_DP LOG_STREAM(warn, log_display)
static lg::log_domain log_help("help");
#define ERR_HP LOG_STREAM(err, log_help)
#define WRN_HP LOG_STREAM(warn, log_help)
#define DBG_HP LOG_STREAM(debug, log_help)
namespace help {
help_text_area::help_text_area(const section &toplevel) :
gui::scrollarea(),
items_(),
last_row_(),
toplevel_(toplevel),
shown_topic_(nullptr),
title_spacing_(16),
curr_loc_(0, 0),
min_row_height_(4 + font::get_max_height(normal_font_size)),
curr_row_height_(min_row_height_),
contents_height_(0)
{
set_scroll_rate(40);
}
void help_text_area::set_inner_location(const SDL_Rect& /*rect*/)
{
if (shown_topic_)
set_items();
}
void help_text_area::show_topic(const topic &t)
{
shown_topic_ = &t;
set_items();
queue_redraw();
DBG_HP << "Showing topic: " << t.id << ": " << t.title;
}
help_text_area::item::item(const texture& _tex, int x, int y, const std::string& _text,
const std::string& reference_to, bool _floating,
bool _box, ALIGNMENT alignment) :
rect_(),
tex(_tex),
text(_text),
ref_to(reference_to),
floating(_floating), box(_box),
align(alignment)
{
rect_.x = x;
rect_.y = y;
rect_.w = box ? tex.w() + box_width * 2 : tex.w();
rect_.h = box ? tex.h() + box_width * 2 : tex.h();
}
help_text_area::item::item(const texture& _tex, int x, int y, bool _floating,
bool _box, ALIGNMENT alignment) :
rect_(),
tex(_tex),
text(""),
ref_to(""),
floating(_floating),
box(_box), align(alignment)
{
rect_.x = x;
rect_.y = y;
rect_.w = box ? tex.w() + box_width * 2 : tex.w();
rect_.h = box ? tex.h() + box_width * 2 : tex.h();
}
void help_text_area::set_items()
{
last_row_.clear();
items_.clear();
curr_loc_.first = 0;
curr_loc_.second = 0;
curr_row_height_ = min_row_height_;
// Add the title item.
const std::string show_title = font::pango_line_ellipsize(
shown_topic_->title, title_size, inner_location().w);
texture tex(font::pango_render_text(show_title, title_size,
font::NORMAL_COLOR, font::pango_text::STYLE_BOLD));
if (tex) {
add_item(item(tex, 0, 0, show_title));
curr_loc_.second = title_spacing_;
contents_height_ = title_spacing_;
down_one_line();
}
// Parse and add the text.
const config& parsed_items = shown_topic_->text.parsed_text();
for(auto item : parsed_items.all_children_range()) {
#define TRY(name) do { \
if (item.key == #name) \
handle_##name##_cfg(item.cfg); \
} while (0)
TRY(text);
TRY(ref);
TRY(img);
TRY(bold);
TRY(italic);
TRY(header);
TRY(jump);
TRY(format);
#undef TRY
}
down_one_line(); // End the last line.
int h = height();
set_position(0);
set_full_size(contents_height_);
set_shown_size(h);
}
void help_text_area::handle_ref_cfg(const config &cfg)
{
const std::string dst = cfg["dst"];
const std::string text = cfg["text"];
bool force = cfg["force"].to_bool();
if (dst.empty()) {
std::stringstream msg;
msg << "Ref markup must have dst attribute. Please submit a bug"
" report if you have not modified the game files yourself. Erroneous config: ";
write(msg, cfg);
throw parse_error(msg.str());
}
if (find_topic(toplevel_, dst) == nullptr && !force) {
// detect the broken link but quietly silence the hyperlink for normal user
add_text_item(text, game_config::debug ? dst : "", true);
// FIXME: workaround: if different campaigns define different
// terrains, some terrains available in one campaign will
// appear in the list of seen terrains, and be displayed in the
// help, even if the current campaign does not handle such
// terrains. This will lead to the unit page generator creating
// invalid references.
//
// Disabling this is a kludgey workaround until the
// encountered_terrains system is fixed
//
// -- Ayin apr 8 2005
#if 0
if (game_config::debug) {
std::stringstream msg;
msg << "Reference to non-existent topic '" << dst
<< "'. Please submit a bug report if you have not"
"modified the game files yourself. Erroneous config: ";
write(msg, cfg);
throw parse_error(msg.str());
}
#endif
} else {
add_text_item(text, dst);
}
}
void help_text_area::handle_img_cfg(const config &cfg)
{
const std::string src = cfg["src"];
const std::string align = cfg["align"];
bool floating = cfg["float"].to_bool();
bool box = cfg["box"].to_bool(true);
if (src.empty()) {
throw parse_error("Img markup must have src attribute.");
}
add_img_item(src, align, floating, box);
}
void help_text_area::handle_bold_cfg(const config &cfg)
{
const std::string text = cfg["text"];
if (text.empty()) {
throw parse_error("Bold markup must have text attribute.");
}
add_text_item(text, "", false, -1, true);
}
void help_text_area::handle_italic_cfg(const config &cfg)
{
const std::string text = cfg["text"];
if (text.empty()) {
throw parse_error("Italic markup must have text attribute.");
}
add_text_item(text, "", false, -1, false, true);
}
void help_text_area::handle_header_cfg(const config &cfg)
{
const std::string text = cfg["text"];
if (text.empty()) {
throw parse_error("Header markup must have text attribute.");
}
add_text_item(text, "", false, title2_size, true);
}
void help_text_area::handle_jump_cfg(const config &cfg)
{
const std::string amount_str = cfg["amount"];
const std::string to_str = cfg["to"];
if (amount_str.empty() && to_str.empty()) {
throw parse_error("Jump markup must have either a to or an amount attribute.");
}
unsigned jump_to = curr_loc_.first;
if (!amount_str.empty()) {
unsigned amount;
try {
amount = lexical_cast<unsigned, std::string>(amount_str);
}
catch (bad_lexical_cast&) {
throw parse_error("Invalid amount the amount attribute in jump markup.");
}
jump_to += amount;
}
if (!to_str.empty()) {
unsigned to;
try {
to = lexical_cast<unsigned, std::string>(to_str);
}
catch (bad_lexical_cast&) {
throw parse_error("Invalid amount in the to attribute in jump markup.");
}
if (to < jump_to) {
down_one_line();
}
jump_to = to;
}
if (jump_to != 0 && static_cast<int>(jump_to) <
get_max_x(curr_loc_.first, curr_row_height_)) {
curr_loc_.first = jump_to;
}
}
void help_text_area::handle_format_cfg(const config &cfg)
{
const std::string text = cfg["text"];
if (text.empty()) {
throw parse_error("Format markup must have text attribute.");
}
bool bold = cfg["bold"].to_bool();
bool italic = cfg["italic"].to_bool();
int font_size = cfg["font_size"].to_int(normal_font_size);
color_t color = font::string_to_color(cfg["color"]);
add_text_item(text, "", false, font_size, bold, italic, color);
}
void help_text_area::handle_text_cfg(const config& cfg) {
add_text_item(cfg["text"]);
}
void help_text_area::add_text_item(const std::string& text, const std::string& ref_dst,
bool broken_link, int _font_size, bool bold, bool italic,
color_t text_color
)
{
const int font_size = _font_size < 0 ? normal_font_size : _font_size;
// font::line_width(), font::get_rendered_text() are not use scaled font inside
const int scaled_font_size = prefs::get().font_scaled(font_size);
if (text.empty())
return;
const int remaining_width = get_remaining_width();
std::size_t first_word_start = text.find_first_not_of(" ");
if (first_word_start == std::string::npos) {
first_word_start = 0;
}
if (text[first_word_start] == '\n') {
down_one_line();
std::string rest_text = text;
rest_text.erase(0, first_word_start + 1);
add_text_item(rest_text, ref_dst, broken_link, _font_size, bold, italic, text_color);
return;
}
const std::string first_word = get_first_word(text);
int state = font::pango_text::STYLE_NORMAL;
state |= bold ? font::pango_text::STYLE_BOLD : 0;
state |= italic ? font::pango_text::STYLE_ITALIC : 0;
if (curr_loc_.first != get_min_x(curr_loc_.second, curr_row_height_)
&& remaining_width < font::pango_line_width(first_word, scaled_font_size, font::pango_text::FONT_STYLE(state))) {
// The first word does not fit, and we are not at the start of
// the line. Move down.
down_one_line();
std::string s = remove_first_space(text);
add_text_item(s, ref_dst, broken_link, _font_size, bold, italic, text_color);
}
else {
std::vector<std::string> parts = split_in_width(text, font_size, remaining_width);
std::string first_part = parts.front();
// Always override the color if we have a cross reference.
color_t color;
if(ref_dst.empty())
color = text_color;
else if(broken_link)
color = font::BAD_COLOR;
else
color = font::YELLOW_COLOR;
// In split_in_width(), no_break_after() and no_break_before() are used(see marked-up_text.cpp).
// Thus, even if there is enough remaining_width for the next word,
// sometimes empty string is returned from split_in_width().
if (first_part.empty()) {
down_one_line();
}
else {
texture tex(font::pango_render_text(first_part,
scaled_font_size, color, font::pango_text::FONT_STYLE(state)));
if (tex) {
add_item(item(tex, curr_loc_.first, curr_loc_.second,
first_part, ref_dst));
}
}
if (parts.size() > 1) {
std::string& s = parts.back();
const std::string first_word_before = get_first_word(s);
const std::string first_word_after = get_first_word(remove_first_space(s));
if (get_remaining_width() >= font::pango_line_width(first_word_after, scaled_font_size, font::pango_text::FONT_STYLE(state))
&& get_remaining_width()
< font::pango_line_width(first_word_before, scaled_font_size, font::pango_text::FONT_STYLE(state))) {
// If the removal of the space made this word fit, we
// must move down a line, otherwise it will be drawn
// without a space at the end of the line.
s = remove_first_space(s);
down_one_line();
}
else if (!(font::pango_line_width(first_word_before, scaled_font_size, font::pango_text::FONT_STYLE(state))
< get_remaining_width())) {
s = remove_first_space(s);
}
add_text_item(s, ref_dst, broken_link, _font_size, bold, italic, text_color);
}
}
}
void help_text_area::add_img_item(const std::string& path, const std::string& alignment,
const bool floating, const bool box)
{
texture tex(image::get_texture(path));
if (!tex)
return;
ALIGNMENT align = str_to_align(alignment);
if (align == HERE && floating) {
WRN_DP << "Floating image with align HERE, aligning left.";
align = LEFT;
}
const int width = tex.w() + (box ? box_width * 2 : 0);
int xpos;
int ypos = curr_loc_.second;
int text_width = inner_location().w;
switch (align) {
case HERE:
xpos = curr_loc_.first;
break;
case LEFT:
default:
xpos = 0;
break;
case MIDDLE:
xpos = text_width / 2 - width / 2 - (box ? box_width : 0);
break;
case RIGHT:
xpos = text_width - width - (box ? box_width * 2 : 0);
break;
}
if (curr_loc_.first != get_min_x(curr_loc_.second, curr_row_height_)
&& (xpos < curr_loc_.first || xpos + width > text_width)) {
down_one_line();
add_img_item(path, alignment, floating, box);
}
else {
if (!floating) {
curr_loc_.first = xpos;
}
else {
ypos = get_y_for_floating_img(width, xpos, ypos);
}
add_item(item(tex, xpos, ypos, floating, box, align));
}
}
int help_text_area::get_y_for_floating_img(const int width, const int x, const int desired_y)
{
int min_y = desired_y;
for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
const item& itm = *it;
if (itm.floating) {
if ((itm.rect_.x + itm.rect_.w > x && itm.rect_.x < x + width)
|| (itm.rect_.x > x && itm.rect_.x < x + width)) {
min_y = std::max<int>(min_y, itm.rect_.y + itm.rect_.h);
}
}
}
return min_y;
}
int help_text_area::get_min_x(const int y, const int height)
{
int min_x = 0;
for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
const item& itm = *it;
if (itm.floating) {
if (itm.rect_.y < y + height && itm.rect_.y + itm.rect_.h > y && itm.align == LEFT) {
min_x = std::max<int>(min_x, itm.rect_.w + 5);
}
}
}
return min_x;
}
int help_text_area::get_max_x(const int y, const int height)
{
int text_width = inner_location().w;
int max_x = text_width;
for (std::list<item>::const_iterator it = items_.begin(); it != items_.end(); ++it) {
const item& itm = *it;
if (itm.floating) {
if (itm.rect_.y < y + height && itm.rect_.y + itm.rect_.h > y) {
if (itm.align == RIGHT) {
max_x = std::min<int>(max_x, text_width - itm.rect_.w - 5);
} else if (itm.align == MIDDLE) {
max_x = std::min<int>(max_x, text_width / 2 - itm.rect_.w / 2 - 5);
}
}
}
}
return max_x;
}
void help_text_area::add_item(const item &itm)
{
items_.push_back(itm);
if (!itm.floating) {
curr_loc_.first += itm.rect_.w;
curr_row_height_ = std::max<int>(itm.rect_.h, curr_row_height_);
contents_height_ = std::max<int>(contents_height_, curr_loc_.second + curr_row_height_);
last_row_.push_back(&items_.back());
}
else {
if (itm.align == LEFT) {
curr_loc_.first = itm.rect_.w + 5;
}
contents_height_ = std::max<int>(contents_height_, itm.rect_.y + itm.rect_.h);
}
}
help_text_area::ALIGNMENT help_text_area::str_to_align(const std::string &cmp_str)
{
if (cmp_str == "left") {
return LEFT;
} else if (cmp_str == "middle") {
return MIDDLE;
} else if (cmp_str == "right") {
return RIGHT;
} else if (cmp_str == "here" || cmp_str.empty()) { // Make the empty string be "here" alignment.
return HERE;
}
std::stringstream msg;
msg << "Invalid alignment string: '" << cmp_str << "'";
throw parse_error(msg.str());
}
void help_text_area::down_one_line()
{
adjust_last_row();
last_row_.clear();
curr_loc_.second += curr_row_height_ + (curr_row_height_ == min_row_height_ ? 0 : 2);
curr_row_height_ = min_row_height_;
contents_height_ = std::max<int>(curr_loc_.second + curr_row_height_, contents_height_);
curr_loc_.first = get_min_x(curr_loc_.second, curr_row_height_);
}
void help_text_area::adjust_last_row()
{
for (std::list<item *>::iterator it = last_row_.begin(); it != last_row_.end(); ++it) {
item &itm = *(*it);
const int gap = curr_row_height_ - itm.rect_.h;
itm.rect_.y += gap / 2;
}
}
int help_text_area::get_remaining_width()
{
const int total_w = get_max_x(curr_loc_.second, curr_row_height_);
return total_w - curr_loc_.first;
}
void help_text_area::draw_contents()
{
const SDL_Rect& loc = inner_location();
auto clipper = draw::reduce_clip(loc);
for(std::list<item>::const_iterator it = items_.begin(), end = items_.end(); it != end; ++it) {
SDL_Rect dst = it->rect_;
dst.y -= get_position();
if (dst.y < static_cast<int>(loc.h) && dst.y + it->rect_.h > 0) {
dst.x += loc.x;
dst.y += loc.y;
if (it->box) {
for (int i = 0; i < box_width; ++i) {
SDL_Rect draw_rect {
dst.x,
dst.y,
it->rect_.w - i * 2,
it->rect_.h - i * 2
};
draw::fill(draw_rect, 0, 0, 0, 0);
++dst.x;
++dst.y;
}
}
draw::blit(it->tex, dst);
}
}
}
void help_text_area::scroll(unsigned int)
{
// Nothing will be done on the actual scroll event. The scroll
// position is checked when drawing instead and things drawn
// accordingly.
queue_redraw();
}
bool help_text_area::item_at::operator()(const item& item) const {
return item.rect_.contains(x_, y_);
}
std::string help_text_area::ref_at(const int x, const int y)
{
const int local_x = x - location().x;
const int local_y = y - location().y;
if (local_y < height() && local_y > 0) {
const int cmp_y = local_y + get_position();
const std::list<item>::const_iterator it =
std::find_if(items_.begin(), items_.end(), item_at(local_x, cmp_y));
if (it != items_.end()) {
if (!(*it).ref_to.empty()) {
return ((*it).ref_to);
}
}
}
return "";
}
} // end namespace help

View File

@ -1,177 +0,0 @@
/*
Copyright (C) 2003 - 2024
by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project https://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#pragma once
#include <list> // for list
#include <string> // for string
#include <utility> // for pair
#include "font/standard_colors.hpp" // for NORMAL_COLOR
#include "sdl/texture.hpp" // for texture
#include "widgets/scrollarea.hpp" // for scrollarea
class config;
namespace help { struct section; }
namespace help { struct topic; }
namespace help {
/** The area where the content is shown in the help browser. */
class help_text_area : public gui::scrollarea
{
public:
help_text_area(const section &toplevel);
/** Display the topic. */
void show_topic(const topic &t);
/**
* Return the ID that is cross-referenced at the (screen)
* coordinates x, y. If no cross-reference is there, return the
* empty string.
*/
std::string ref_at(const int x, const int y);
protected:
virtual void scroll(unsigned int pos);
virtual void set_inner_location(const SDL_Rect& rect);
private:
enum ALIGNMENT {LEFT, MIDDLE, RIGHT, HERE};
/** Convert a string to an alignment. Throw parse_error if unsuccessful. */
ALIGNMENT str_to_align(const std::string &s);
/**
* An item that is displayed in the text area. Contains the surface
* that should be blitted along with some other information.
*/
struct item {
item(const texture& tex, int x, int y, const std::string& text="",
const std::string& reference_to="", bool floating=false,
bool box=false, ALIGNMENT alignment=HERE);
item(const texture& tex, int x, int y,
bool floating, bool box=false, ALIGNMENT=HERE);
/** Relative coordinates of this item. */
rect rect_;
texture tex;
// If this item contains text, this will contain that text.
std::string text;
// If this item contains a cross-reference, this is the id
// of the referenced topic.
std::string ref_to;
// If this item is floating, that is, if things should be filled
// around it.
bool floating;
bool box;
ALIGNMENT align;
};
/** Function object to find an item at the specified coordinates. */
class item_at {
public:
item_at(const int x, const int y) : x_(x), y_(y) {}
bool operator()(const item&) const;
private:
const int x_, y_;
};
/**
* Update the vector with the items of the shown topic, creating
* surfaces for everything and putting things where they belong.
*/
void set_items();
// Create appropriate items from configs. Items will be added to the
// internal vector. These methods check that the necessary
// attributes are specified.
void handle_ref_cfg(const config &cfg);
void handle_img_cfg(const config &cfg);
void handle_bold_cfg(const config &cfg);
void handle_italic_cfg(const config &cfg);
void handle_header_cfg(const config &cfg);
void handle_jump_cfg(const config &cfg);
void handle_format_cfg(const config &cfg);
void handle_text_cfg(const config &cfg);
void draw_contents();
/**
* Add an item with text. If ref_dst is something else than the
* empty string, the text item will be underlined to show that it
* is a cross-reference. The item will also remember what the
* reference points to. If font_size is below zero, the default
* will be used.
*/
void add_text_item(const std::string& text, const std::string& ref_dst="",
bool broken_link = false,
int font_size=-1, bool bold=false, bool italic=false,
color_t color=font::NORMAL_COLOR);
/** Add an image item with the specified attributes. */
void add_img_item(const std::string& path, const std::string& alignment, const bool floating,
const bool box);
/** Move the current input point to the next line. */
void down_one_line();
/** Adjust the heights of the items in the last row to make it look good. */
void adjust_last_row();
/** Return the width that remain on the line the current input point is at. */
int get_remaining_width();
/**
* Return the least x coordinate at which something of the
* specified height can be drawn at the specified y coordinate
* without interfering with floating images.
*/
int get_min_x(const int y, const int height=0);
/** Analogous with get_min_x but return the maximum X. */
int get_max_x(const int y, const int height=0);
/**
* Find the lowest y coordinate where a floating img of the
* specified width and at the specified x coordinate can be
* placed. Start looking at desired_y and continue downwards. Only
* check against other floating things, since text and inline
* images only can be above this place if called correctly.
*/
int get_y_for_floating_img(const int width, const int x, const int desired_y);
/** Add an item to the internal list, update the locations and row height. */
void add_item(const item& itm);
std::list<item> items_;
std::list<item *> last_row_;
const section &toplevel_;
topic const *shown_topic_;
const int title_spacing_;
/** The current input location when creating items. */
std::pair<int, int> curr_loc_;
const unsigned min_row_height_;
unsigned curr_row_height_;
/** The height of all items in total. */
int contents_height_;
};
} // end namespace help