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