26#include <SDL3_ttf/SDL_ttf.h>
28#include "sdl_widget.hpp"
29#include "sdl_blend_mode_guard.hpp"
30#include "../sdl_utils.hpp"
32#include "res/sdl3_resource_manager.hpp"
34#include <freerdp/log.h>
36#if defined(WITH_SDL_IMAGE_DIALOGS)
37#include <SDL3_image/SDL_image.h>
40#define TAG CLIENT_TAG("SDL.widget")
42static const Uint32 hpadding = 10;
44SdlWidget::SdlWidget(std::shared_ptr<SDL_Renderer>& renderer,
const SDL_FRect& rect)
45 : _renderer(renderer),
46 _engine(TTF_CreateRendererTextEngine(renderer.get()), TTF_DestroyRendererTextEngine),
52 "OpenSans-VariableFont_wdth,wght.ttf");
54 widget_log_error(
false,
"SDLResourceManager::get");
57 _font = std::shared_ptr<TTF_Font>(TTF_OpenFontIO(ops,
true, 64), TTF_CloseFont);
59 widget_log_error(
false,
"TTF_OpenFontRW");
63#if defined(WITH_SDL_IMAGE_DIALOGS)
64SdlWidget::SdlWidget(std::shared_ptr<SDL_Renderer>& renderer,
const SDL_FRect& rect,
66 : _renderer(renderer),
67 _engine(TTF_CreateRendererTextEngine(renderer.get()), TTF_DestroySurfaceTextEngine),
72 _image = std::shared_ptr<SDL_Texture>(IMG_LoadTexture_IO(renderer.get(), ops, 1),
75 widget_log_error(
false,
"IMG_LoadTexture_IO");
80SdlWidget::SdlWidget(
SdlWidget&& other) noexcept
81 : _renderer(std::move(other._renderer)), _backgroundcolor(other._backgroundcolor),
82 _fontcolor(other._fontcolor), _text(std::move(other._text)), _font(std::move(other._font)),
83 _image(std::move(other._image)), _engine(std::move(other._engine)), _rect(other._rect),
84 _wrap(other._wrap), _text_width(other._text_width)
86 other._font =
nullptr;
87 other._image =
nullptr;
88 other._engine =
nullptr;
91std::shared_ptr<SDL_Texture> SdlWidget::render_text(
const std::string& text, SDL_Color fgcolor,
92 SDL_FRect& src, SDL_FRect& dst)
const
94 auto surface = std::shared_ptr<SDL_Surface>(
95 TTF_RenderText_Blended(_font.get(), text.c_str(), 0, fgcolor), SDL_DestroySurface);
98 widget_log_error(
false,
"TTF_RenderText_Blended");
102 auto texture = std::shared_ptr<SDL_Texture>(
103 SDL_CreateTextureFromSurface(_renderer.get(), surface.get()), SDL_DestroyTexture);
106 widget_log_error(
false,
"SDL_CreateTextureFromSurface");
112 widget_log_error(
false,
"TTF_CreateRendererTextEngine");
116 std::unique_ptr<TTF_Text,
decltype(&TTF_DestroyText)> txt(
117 TTF_CreateText(_engine.get(), _font.get(), text.c_str(), text.size()), TTF_DestroyText);
121 widget_log_error(
false,
"TTF_CreateText");
126 if (!TTF_GetTextSize(txt.get(), &w, &h))
128 widget_log_error(
false,
"TTF_GetTextSize");
132 src.w =
static_cast<float>(w);
133 src.h =
static_cast<float>(h);
141 dst.w -= 2 * hpadding;
142 const float scale = dst.h / src.h;
143 const float sws = (src.w) * scale;
144 const float dws = (dst.w) / scale;
145 dst.w = std::min(dst.w, sws);
154static float scale(
float dw,
float dh)
156 const auto scale = dh / dw;
157 const auto dr = dh * scale;
161std::shared_ptr<SDL_Texture> SdlWidget::render_text_wrapped(
const std::string& text,
162 SDL_Color fgcolor, SDL_FRect& src,
163 SDL_FRect& dst)
const
165 assert(_text_width < INT32_MAX);
167 auto surface = std::shared_ptr<SDL_Surface>(
168 TTF_RenderText_Blended_Wrapped(_font.get(), text.c_str(), 0, fgcolor,
169 static_cast<int>(_text_width)),
173 widget_log_error(
false,
"TTF_RenderText_Blended");
177 src.w =
static_cast<float>(surface->w);
178 src.h =
static_cast<float>(surface->h);
180 auto texture = std::shared_ptr<SDL_Texture>(
181 SDL_CreateTextureFromSurface(_renderer.get(), surface.get()), SDL_DestroyTexture);
184 widget_log_error(
false,
"SDL_CreateTextureFromSurface");
195 dst.w -= 2 * hpadding;
196 auto dh = scale(src.w, src.h);
197 dst.h = std::min<float>(dh, dst.h);
202SdlWidget::~SdlWidget() =
default;
204bool SdlWidget::error_ex(
bool success,
const char* what,
const char* file,
size_t line,
212 static wLog* log =
nullptr;
217 return sdl_log_error_ex(-1, log, what, file, line, fkt);
220bool SdlWidget::updateInternal()
222 return update_text(_text);
225bool SdlWidget::draw_rect(
const SDL_FRect& rect, SDL_Color color)
const
227 const auto drc = SDL_SetRenderDrawColor(_renderer.get(), color.r, color.g, color.b, color.a);
228 if (widget_log_error(drc,
"SDL_SetRenderDrawColor"))
231 const auto rc = SDL_RenderFillRect(_renderer.get(), &rect);
232 return !widget_log_error(rc,
"SDL_RenderFillRect");
235bool SdlWidget::fill(SDL_Color color)
const
237 std::vector<SDL_Color> colors = { color };
241bool SdlWidget::fill(
const std::vector<SDL_Color>& colors)
const
245 for (
auto color : colors)
247 if (!draw_rect(_rect, color))
250 if (!guard.update(SDL_BLENDMODE_ADD))
257bool SdlWidget::wrap()
const
262bool SdlWidget::set_wrap(
bool wrap,
size_t width)
269const SDL_FRect& SdlWidget::rect()
const
274bool SdlWidget::clear()
const
281 const auto drc = SDL_SetRenderDrawColor(_renderer.get(), _backgroundcolor.r, _backgroundcolor.g,
282 _backgroundcolor.b, _backgroundcolor.a);
283 if (widget_log_error(drc,
"SDL_SetRenderDrawColor"))
286 const auto rcls = SDL_RenderRect(_renderer.get(), &_rect);
287 return !widget_log_error(rcls,
"SDL_RenderRect");
290bool SdlWidget::update()
295 return updateInternal();
298bool SdlWidget::update_text(
const std::string& text)
307 std::shared_ptr<SDL_Texture> texture;
312 auto propId = SDL_GetTextureProperties(_image.get());
313 auto w = SDL_GetNumberProperty(propId, SDL_PROP_TEXTURE_WIDTH_NUMBER, -1);
314 auto h = SDL_GetNumberProperty(propId, SDL_PROP_TEXTURE_HEIGHT_NUMBER, -1);
316 widget_log_error(
false,
"SDL_GetTextureProperties");
317 src.w =
static_cast<float>(w);
318 src.h =
static_cast<float>(h);
321 texture = render_text_wrapped(_text, _fontcolor, src, dst);
323 texture = render_text(_text, _fontcolor, src, dst);
327 const auto rc = SDL_RenderTexture(_renderer.get(), texture.get(), &src, &dst);
328 return !widget_log_error(rc,
"SDL_RenderCopy");
static SDL_IOStream * get(const std::string &type, const std::string &id)
static std::string typeFonts()