diff --git a/src/text.cpp b/src/text.cpp index 7636f07a1488..ec3c559af799 100644 --- a/src/text.cpp +++ b/src/text.cpp @@ -68,6 +68,8 @@ const unsigned ttext::STYLE_BOLD = TTF_STYLE_BOLD; const unsigned ttext::STYLE_ITALIC = TTF_STYLE_ITALIC; const unsigned ttext::STYLE_UNDERLINE = TTF_STYLE_UNDERLINE; +static bool looks_like_url(const std::string & token); + std::string escape_text(const std::string& text) { std::string result; @@ -99,6 +101,7 @@ ttext::ttext() : #endif text_(), markedup_text_(false), + link_aware_(false), font_size_(14), font_style_(STYLE_NORMAL), foreground_color_(0xFFFFFFFF), // solid white @@ -301,6 +304,21 @@ std::string ttext::get_token(const gui2::tpoint & position, const char * delim) return txt.substr(l,r-l); } +std::string ttext::get_link(const gui2::tpoint & position) const +{ + if (!link_aware_) { + return ""; + } + + std::string tok = get_token(position, " \n\r\t"); + + if (looks_like_url(tok)) { + return tok; + } else { + return ""; + } +} + gui2::tpoint ttext::get_column_line(const gui2::tpoint& position) const { recalculate(); @@ -509,6 +527,16 @@ ttext& ttext::set_maximum_length(const size_t maximum_length) return *this; } +ttext& ttext::set_link_aware(bool b) +{ + if (link_aware_ != b) { + calculation_dirty_ = true; + surface_dirty_ = true; + link_aware_ = b; + } + return *this; +} + namespace { /** Small helper class to make sure the font object is destroyed properly. */ @@ -758,7 +786,49 @@ void ttext::create_surface_buffer(const size_t size) const memset(surface_buffer_, 0, size); } -bool ttext::set_markup(const std::string& text) +static std::string handle_token(const std::string & token); + +bool ttext::set_markup(const std::string & text) { + if (!link_aware_) { + return set_markup_helper(text); + } else { + std::string delim = " \n\r\t"; + + // Tokenize according to these delimiters, and stream the results of `handle_token` on each token to get the new text. + + std::stringstream ss; + + int last_delim = -1; + for (size_t index = 0; index < text.size(); ++index) { + if (delim.find(text.at(index)) != std::string::npos) { + ss << handle_token(text.substr(last_delim + 1, index - last_delim - 1)); // want to include chars from range since last token, dont want to include any delimiters + ss << text.at(index); + last_delim = index; + } + } + if (last_delim < static_cast(text.size()) - 1) { + ss << handle_token(text.substr(last_delim + 1, text.size() - last_delim - 1)); + } + + return set_markup_helper(ss.str()); + } +} + +static bool looks_like_url(const std::string & str) +{ + return (str.size() >= 8) && ((str.substr(0,7) == "http://") || (str.substr(0,8) == "https://")); +} + +static std::string handle_token(const std::string & token) +{ + if (looks_like_url(token)) { + return "" + token + ""; + } else { + return token; + } +} + +bool ttext::set_markup_helper(const std::string& text) { if(pango_parse_markup(text.c_str(), text.size() , 0, NULL, NULL, NULL, NULL)) { diff --git a/src/text.hpp b/src/text.hpp index 951f159fe914..c5719699cf75 100644 --- a/src/text.hpp +++ b/src/text.hpp @@ -174,6 +174,15 @@ class ttext */ std::string get_token(const gui2::tpoint & position, const char * delimiters = " \n\r\t") const; + /** + * Checks if position points to a character in a link in the text, returns it + * if so, empty string otherwise. Link-awareness must be enabled to get results. + * @param position The pixel position in the text area. + * + * @returns The link if one is found, the empty string otherwise. + */ + std::string get_link(const gui2::tpoint & position) const; + /** * Gets the column of line of the character at the position. * @@ -231,6 +240,9 @@ class ttext ttext& set_maximum_length(const size_t maximum_length); + bool link_aware() const { return link_aware_; } + + ttext& set_link_aware(bool b); private: /***** ***** ***** ***** Pango variables ***** ***** ***** *****/ @@ -256,6 +268,9 @@ class ttext /** Is the text markedup if so the markedup render routines need to be used. */ bool markedup_text_; + /** Are hyperlinks in the text marked-up, and will get_link return them. */ + bool link_aware_; + /** The font size to draw. */ unsigned font_size_; @@ -381,6 +396,7 @@ class ttext */ bool set_markup(const std::string& text); + bool set_markup_helper(const std::string & text); }; } // namespace font