Fixed 'scale to fit' functionality of WidgetImage

This commit is contained in:
nedko 2025-12-15 16:54:28 +02:00
parent c626578557
commit 17f73211a9
3 changed files with 57 additions and 4 deletions

View File

@ -16,7 +16,6 @@ m_valign(valign),
m_bg_color(bg_color)
{
m_image_surface = IMG_Load(m_filename.c_str());
if (nullptr == m_image_surface)
{
// TODO: Print errors
@ -39,16 +38,23 @@ void WidgetImage::draw()
return;
}
SDL_Rect align = surface_align(m_surface, m_image_surface, m_halign, m_valign);
SDL_Rect align;
SDL_Surface* scaled_image = nullptr;
switch (m_resize_type)
{
case RESIZE_NONE:
align = surface_align(m_surface, m_image_surface, m_halign, m_valign);
SDL_BlitSurface(m_image_surface, nullptr, m_surface, &align);
break;
case RESIZE_FIT:
// TODO: This currently stretches
SDL_BlitScaled(m_image_surface, nullptr, m_surface, nullptr);
scaled_image = image_scale_fit();
if (nullptr != scaled_image)
{
align = surface_align(m_surface, scaled_image, m_halign, m_valign);
SDL_BlitScaled(scaled_image, nullptr, m_surface, &align);
SDL_FreeSurface(scaled_image);
}
break;
case RESIZE_STRETCH:
@ -82,3 +88,41 @@ std::unique_ptr<Widget> WidgetImage::builder(const nlohmann::json& j)
return std::make_unique<WidgetImage>(x, y, width, height, filename,
resize_type, halign, valign, bg_color);
}
SDL_Surface* WidgetImage::image_scale_fit()
{
SDL_Rect align = {.x = 0, .y = 0, .w = 0, .h = 0};
if ((nullptr == m_surface) || (nullptr == m_image_surface))
{
return nullptr;
}
double x_scale = m_surface->w;
x_scale /= m_image_surface->w;
double y_scale = m_surface->h;
y_scale /= m_image_surface->h;
// Find smallest scale factor
double min_scale = x_scale;
if (y_scale < min_scale)
{
min_scale = y_scale;
}
// Scale with double in the front and then clamp to int via SDL_Rect
align.w = min_scale * m_image_surface->w;
align.h = min_scale * m_image_surface->h;
SDL_Surface* scaled_image_surface =
SDL_CreateRGBSurfaceWithFormat(0, align.w, align.h, 32, SDL_PIXELFORMAT_RGBA8888);
if (nullptr == scaled_image_surface)
{
// TODO: Print Error
return nullptr;
}
SDL_BlitScaled(m_image_surface, nullptr, scaled_image_surface, nullptr);
return scaled_image_surface;
}

View File

@ -42,6 +42,11 @@ public:
virtual void draw() override;
static std::unique_ptr<Widget> builder(const nlohmann::json& j);
protected:
// Create a new surface of the image_surface that is scaled via RESIZE_FIT method
// NOTE: The user MUST free the surface when done with it
SDL_Surface* image_scale_fit();
};
#endif // WIDGET_IMAGE_H_

View File

@ -87,6 +87,10 @@ SDL_Rect surface_align(const SDL_Surface* base, const SDL_Surface* applied,
return align;
}
// These are set in order to handle scaled blits
align.w = applied->w;
align.h = applied->h;
if (nullptr == hint_external)
{
hint = SDL_Rect{.x = 0, .y = 0, .w = applied->w, .h = applied->h};