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