FreeRDP
SDL2/dialogs/sdl_widget.cpp
1 
20 #include <cassert>
21 #include <cstdio>
22 #include <cstdlib>
23 
24 #include <SDL.h>
25 #include <SDL_ttf.h>
26 
27 #include "sdl_widget.hpp"
28 #include "../sdl_utils.hpp"
29 
30 #include "res/sdl2_resource_manager.hpp"
31 
32 #include <freerdp/log.h>
33 
34 #if defined(WITH_SDL_IMAGE_DIALOGS)
35 #include <SDL_image.h>
36 #endif
37 
38 #define TAG CLIENT_TAG("SDL.widget")
39 
40 static const SDL_Color backgroundcolor = { 0x38, 0x36, 0x35, 0xff };
41 
42 static const Uint32 hpadding = 10;
43 
44 SdlWidget::SdlWidget(SDL_Renderer* renderer, SDL_Rect rect, bool input) : _rect(rect), _input(input)
45 {
46  assert(renderer);
47 
49  "OpenSans-VariableFont_wdth,wght.ttf");
50  if (!ops)
51  widget_log_error(-1, "SDLResourceManager::get");
52  else
53  {
54  _font = TTF_OpenFontRW(ops, 1, 64);
55  if (!_font)
56  widget_log_error(-1, "TTF_OpenFontRW");
57  }
58 }
59 
60 #if defined(WITH_SDL_IMAGE_DIALOGS)
61 SdlWidget::SdlWidget(SDL_Renderer* renderer, SDL_Rect rect, SDL_RWops* ops) : _rect(rect)
62 {
63  if (ops)
64  {
65  _image = IMG_LoadTexture_RW(renderer, ops, 1);
66  if (!_image)
67  widget_log_error(-1, "IMG_LoadTextureTyped_RW");
68  }
69 }
70 #endif
71 
72 SdlWidget::SdlWidget(SdlWidget&& other) noexcept
73  : _font(other._font), _image(other._image), _rect(other._rect), _input(other._input),
74  _wrap(other._wrap), _text_width(other._text_width)
75 {
76  other._font = nullptr;
77  other._image = nullptr;
78 }
79 
80 SDL_Texture* SdlWidget::render_text(SDL_Renderer* renderer, const std::string& text,
81  SDL_Color fgcolor, SDL_Rect& src, SDL_Rect& dst)
82 {
83  auto surface = TTF_RenderUTF8_Blended(_font, text.c_str(), fgcolor);
84  if (!surface)
85  {
86  widget_log_error(-1, "TTF_RenderText_Blended");
87  return nullptr;
88  }
89 
90  auto texture = SDL_CreateTextureFromSurface(renderer, surface);
91  SDL_FreeSurface(surface);
92  if (!texture)
93  {
94  widget_log_error(-1, "SDL_CreateTextureFromSurface");
95  return nullptr;
96  }
97 
98  TTF_SizeUTF8(_font, text.c_str(), &src.w, &src.h);
99 
100  /* Do some magic:
101  * - Add padding before and after text
102  * - if text is too long only show the last elements
103  * - if text is too short only update used space
104  */
105  dst = _rect;
106  dst.x += hpadding;
107  dst.w -= 2 * hpadding;
108  const auto scale = static_cast<float>(dst.h) / static_cast<float>(src.h);
109  const auto sws = static_cast<float>(src.w) * scale;
110  const auto dws = static_cast<float>(dst.w) / scale;
111  if (static_cast<float>(dst.w) > sws)
112  dst.w = static_cast<int>(sws);
113  if (static_cast<float>(src.w) > dws)
114  {
115  src.x = src.w - static_cast<int>(dws);
116  src.w = static_cast<int>(dws);
117  }
118  return texture;
119 }
120 
121 static int scale(int w, int h)
122 {
123  const auto dw = static_cast<double>(w);
124  const auto dh = static_cast<double>(h);
125  const auto scale = dh / dw;
126  const auto dr = dh * scale;
127  return static_cast<int>(dr);
128 }
129 
130 SDL_Texture* SdlWidget::render_text_wrapped(SDL_Renderer* renderer, const std::string& text,
131  SDL_Color fgcolor, SDL_Rect& src, SDL_Rect& dst)
132 {
133  Sint32 w = 0;
134  Sint32 h = 0;
135  TTF_SizeUTF8(_font, " ", &w, &h);
136 
137  assert(_text_width <= UINT32_MAX);
138  auto surface = TTF_RenderUTF8_Blended_Wrapped(_font, text.c_str(), fgcolor,
139  static_cast<Uint32>(_text_width));
140  if (!surface)
141  {
142  widget_log_error(-1, "TTF_RenderText_Blended");
143  return nullptr;
144  }
145 
146  src.w = surface->w;
147  src.h = surface->h;
148 
149  auto texture = SDL_CreateTextureFromSurface(renderer, surface);
150  SDL_FreeSurface(surface);
151  if (!texture)
152  {
153  widget_log_error(-1, "SDL_CreateTextureFromSurface");
154  return nullptr;
155  }
156 
157  /* Do some magic:
158  * - Add padding before and after text
159  * - if text is too long only show the last elements
160  * - if text is too short only update used space
161  */
162  dst = _rect;
163  dst.x += hpadding;
164  dst.w -= 2 * hpadding;
165  auto dh = scale(src.w, src.h);
166  if (dh < dst.h)
167  dst.h = dh;
168 
169  return texture;
170 }
171 
172 SdlWidget::~SdlWidget()
173 {
174  TTF_CloseFont(_font);
175  if (_image)
176  SDL_DestroyTexture(_image);
177 }
178 
179 bool SdlWidget::error_ex(Uint32 res, const char* what, const char* file, size_t line,
180  const char* fkt)
181 {
182  static wLog* log = nullptr;
183  if (!log)
184  log = WLog_Get(TAG);
185  return sdl_log_error_ex(res, log, what, file, line, fkt);
186 }
187 
188 static bool draw_rect(SDL_Renderer* renderer, const SDL_Rect* rect, SDL_Color color)
189 {
190  const int drc = SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
191  if (widget_log_error(drc, "SDL_SetRenderDrawColor"))
192  return false;
193 
194  const int rc = SDL_RenderFillRect(renderer, rect);
195  return !widget_log_error(rc, "SDL_RenderFillRect");
196 }
197 
198 bool SdlWidget::fill(SDL_Renderer* renderer, SDL_Color color)
199 {
200  std::vector<SDL_Color> colors = { color };
201  return fill(renderer, colors);
202 }
203 
204 bool SdlWidget::fill(SDL_Renderer* renderer, const std::vector<SDL_Color>& colors)
205 {
206  assert(renderer);
207  SDL_BlendMode mode = SDL_BLENDMODE_INVALID;
208  SDL_GetRenderDrawBlendMode(renderer, &mode);
209  SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
210  for (auto color : colors)
211  {
212  draw_rect(renderer, &_rect, color);
213  SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_ADD);
214  }
215  SDL_SetRenderDrawBlendMode(renderer, mode);
216  return true;
217 }
218 
219 bool SdlWidget::update_text(SDL_Renderer* renderer, const std::string& text, SDL_Color fgcolor,
220  SDL_Color bgcolor)
221 {
222  assert(renderer);
223 
224  if (!fill(renderer, bgcolor))
225  return false;
226  return update_text(renderer, text, fgcolor);
227 }
228 
229 bool SdlWidget::wrap() const
230 {
231  return _wrap;
232 }
233 
234 bool SdlWidget::set_wrap(bool wrap, size_t width)
235 {
236  _wrap = wrap;
237  _text_width = width;
238  return _wrap;
239 }
240 
241 const SDL_Rect& SdlWidget::rect() const
242 {
243  return _rect;
244 }
245 
246 bool SdlWidget::update_text(SDL_Renderer* renderer, const std::string& text, SDL_Color fgcolor)
247 {
248 
249  if (text.empty())
250  return true;
251 
252  SDL_Rect src{};
253  SDL_Rect dst{};
254 
255  SDL_Texture* texture = nullptr;
256  if (_image)
257  {
258  texture = _image;
259  dst = _rect;
260  auto rc = SDL_QueryTexture(_image, nullptr, nullptr, &src.w, &src.h);
261  if (rc < 0)
262  widget_log_error(rc, "SDL_QueryTexture");
263  }
264  else if (_wrap)
265  texture = render_text_wrapped(renderer, text, fgcolor, src, dst);
266  else
267  texture = render_text(renderer, text, fgcolor, src, dst);
268  if (!texture)
269  return false;
270 
271  const int rc = SDL_RenderCopy(renderer, texture, &src, &dst);
272  if (!_image)
273  SDL_DestroyTexture(texture);
274  if (rc < 0)
275  return !widget_log_error(rc, "SDL_RenderCopy");
276  return true;
277 }
278 
279 bool clear_window(SDL_Renderer* renderer)
280 {
281  assert(renderer);
282 
283  const int drc = SDL_SetRenderDrawColor(renderer, backgroundcolor.r, backgroundcolor.g,
284  backgroundcolor.b, backgroundcolor.a);
285  if (widget_log_error(drc, "SDL_SetRenderDrawColor"))
286  return false;
287 
288  const int rcls = SDL_RenderClear(renderer);
289  return !widget_log_error(rcls, "SDL_RenderClear");
290 }
static SDL_RWops * get(const std::string &type, const std::string &id)
static std::string typeFonts()