The Battle for Wesnoth  1.17.0-dev
sdl_ttf_compat.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2021 - 2021
3  by Iris Morelle <shadowm@wesnoth.org>
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 "font/sdl_ttf_compat.hpp"
17 
18 #include "font/standard_colors.hpp"
19 #include "log.hpp"
20 #include "sdl/point.hpp"
21 #include "sdl/utils.hpp"
23 #include "tooltips.hpp"
24 #include "video.hpp"
25 
26 static lg::log_domain log_font("font");
27 #define DBG_FT LOG_STREAM(debug, log_font)
28 #define LOG_FT LOG_STREAM(info, log_font)
29 #define WRN_FT LOG_STREAM(warn, log_font)
30 #define ERR_FT LOG_STREAM(err, log_font)
31 
32 namespace font {
33 
34 namespace {
35 
36 pango_text& private_renderer()
37 {
38  // Use a separate renderer for GUI1 in case of shenanigans.
39  static pango_text text_renderer;
40  return text_renderer;
41 }
42 
43 }
44 
45 surface pango_render_text(const std::string& text, int size, const color_t& color, font::pango_text::FONT_STYLE style, bool use_markup, int max_width)
46 {
47  auto& ptext = private_renderer();
48 
49  ptext.set_text(text, use_markup);
50  ptext.set_family_class(font::FONT_SANS_SERIF)
51  .set_font_size(size)
52  .set_font_style(style)
53  .set_maximum_height(-1, false)
54  .set_foreground_color(color)
55  .set_maximum_width(max_width)
56  .set_ellipse_mode(max_width > 0 ? PANGO_ELLIPSIZE_END : PANGO_ELLIPSIZE_NONE);
57 
58  return ptext.render().clone();
59 }
60 
61 std::pair<int, int> pango_line_size(const std::string& line, int font_size, font::pango_text::FONT_STYLE font_style)
62 {
63  auto& ptext = private_renderer();
64 
65  ptext.set_text(line, false);
66  ptext.set_family_class(font::FONT_SANS_SERIF)
67  .set_font_size(font_size)
68  .set_font_style(font_style)
69  .set_maximum_height(-1, false)
70  .set_maximum_width(-1)
71  .set_ellipse_mode(PANGO_ELLIPSIZE_NONE);
72 
73  auto s = ptext.get_size();
74  return { s.x, s.y };
75 }
76 
77 std::string pango_line_ellipsize(const std::string& text, int font_size, int max_width, font::pango_text::FONT_STYLE font_style)
78 {
79  if(pango_line_width(text, font_size, font_style) <= max_width) {
80  return text;
81  }
82  if(pango_line_width(font::ellipsis, font_size, font_style) > max_width) {
83  return "";
84  }
85 
86  std::string current_substring;
87 
88  try {
89  utf8::iterator itor(text);
90  for(; itor != utf8::iterator::end(text); ++itor) {
91  std::string tmp = current_substring;
92  tmp.append(itor.substr().first, itor.substr().second);
93 
94  if(pango_line_width(tmp + font::ellipsis, font_size, font_style) > max_width) {
95  return current_substring + font::ellipsis;
96  }
97 
98  current_substring = std::move(tmp);
99  }
100  } catch(const utf8::invalid_utf8_exception&) {
101  WRN_FT << "Invalid UTF-8 string: \"" << text << "\"\n";
102  return "";
103  }
104 
105  return text; // Should not happen
106 }
107 
108 std::string pango_word_wrap(const std::string& unwrapped_text, int font_size, int max_width, int max_height, int max_lines, bool /*partial_line*/)
109 {
110  // FIXME: what the hell does partial_line do in the SDL_ttf version?
111 
112  if(max_lines == 0) {
113  return "";
114  }
115 
116  auto& ptext = private_renderer();
117 
118  ptext.set_text(unwrapped_text, false);
119  ptext.set_family_class(font::FONT_SANS_SERIF)
120  .set_font_size(font_size)
121  .set_font_style(font::pango_text::STYLE_NORMAL)
122  .set_maximum_height(max_height, true)
123  .set_maximum_width(max_width)
124  .set_ellipse_mode(PANGO_ELLIPSIZE_NONE);
125 
126  std::string res;
127  const auto& lines = ptext.get_lines();
128 
129  for(const auto& line : lines) {
130  if(!res.empty())
131  res += '\n';
132  res += line;
133  if(--max_lines == 0)
134  break;
135  }
136 
137  return res;
138 }
139 
140 SDL_Rect pango_draw_text(CVideo* gui, const SDL_Rect& area, int size, const color_t& color, const std::string& text, int x, int y, bool use_tooltips, pango_text::FONT_STYLE style)
141 {
142  static surface null_surf{};
143 
144  return pango_draw_text(gui != nullptr ? gui->getSurface() : null_surf, area, size, color, text, x, y, use_tooltips, style);
145 }
146 
147 SDL_Rect pango_draw_text(surface& dst, const SDL_Rect& area, int size, const color_t& color, const std::string& text, int x, int y, bool use_tooltips, pango_text::FONT_STYLE style)
148 {
149  auto& ptext = private_renderer();
150 
151  ptext.set_text(text, false);
152  ptext.set_family_class(font::FONT_SANS_SERIF)
153  .set_font_size(size)
154  .set_font_style(style)
155  .set_maximum_width(-1)
156  .set_maximum_height(area.h, true)
157  .set_foreground_color(color)
158  .set_ellipse_mode(PANGO_ELLIPSIZE_END);
159 
160  auto extents = ptext.get_size();
161  bool ellipsized = false;
162 
163  if(extents.x > area.w) {
164  ptext.set_maximum_width(area.w);
165  ellipsized = true;
166  }
167 
168  auto s = ptext.render();
169 
170  SDL_Rect res = { x, y, s->w, s->h };
171 
172  if(dst) {
173  SDL_Rect src = { 0, 0, s->w, s->h };
174  sdl_blit(s, &src, dst, &res);
175  }
176 
177  if(ellipsized && use_tooltips) {
178  tooltips::add_tooltip(res, text);
179  }
180 
181  return res;
182 }
183 
184 } // end namespace font
std::string pango_line_ellipsize(const std::string &text, int font_size, int max_width, font::pango_text::FONT_STYLE font_style)
If the text exceeds the specified max width, end it with an ellipsis (...)
Collection of helper functions relating to Pango formatting.
Definition: video.hpp:32
std::pair< int, int > pango_line_size(const std::string &line, int font_size, font::pango_text::FONT_STYLE font_style)
Determine the width and height of a line of text given a certain font size.
General purpose widgets.
#define WRN_FT
surface & getSurface()
Returns a reference to the framebuffer.
Definition: video.cpp:483
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
const std::string ellipsis
Definition: constants.cpp:39
SDL_Rect pango_draw_text(CVideo *gui, const SDL_Rect &area, int size, const color_t &color, const std::string &text, int x, int y, bool use_tooltips, pango_text::FONT_STYLE style)
Draws text on the screen.
const std::pair< typename string_type::const_iterator, typename string_type::const_iterator > & substr() const
std::string pango_word_wrap(const std::string &unwrapped_text, int font_size, int max_width, int max_height, int max_lines, bool)
Uses Pango to word wrap text.
Thrown by operations encountering invalid UTF-8 data.
static map_location::DIRECTION s
static iterator_base end(const string_type &str)
Standard logging facilities (interface).
surface pango_render_text(const std::string &text, int size, const color_t &color, font::pango_text::FONT_STYLE style, bool use_markup, int max_width)
Returns a SDL surface containing the rendered text.
static lg::log_domain log_font("font")
void sdl_blit(const surface &src, SDL_Rect *src_rect, surface &dst, SDL_Rect *dst_rect)
Definition: utils.hpp:32
int add_tooltip(const SDL_Rect &rect, const std::string &message, const std::string &action, bool use_markup, const surface &foreground)
Definition: tooltips.cpp:176
Transitional API for porting SDL_ttf-based code to Pango.
int pango_line_width(const std::string &line, int font_size, font::pango_text::FONT_STYLE font_style=font::pango_text::STYLE_NORMAL)
Determine the width of a line of text given a certain font size.