trmnl_sdl/Widgets/WidgetImage.cpp

129 lines
3.0 KiB
C++

#include "WidgetImage.h"
#include <SDL2/SDL_image.h>
using std::string;
WidgetImage::WidgetImage(int x, int y, int width, int height, string filename,
ImageResize resize_type, HorizontalAlign halign, VerticalAlign valign,
SDL_Color bg_color)
: Widget(x, y, width, height),
m_filename(filename),
m_image_surface(nullptr),
m_resize_type(resize_type),
m_halign(halign),
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
}
}
void WidgetImage::draw()
{
if (nullptr == m_surface)
{
return;
}
// Clear surface with BG color
SDL_FillRect(m_surface, nullptr,
SDL_MapRGBA(m_surface->format, m_bg_color.r, m_bg_color.g, m_bg_color.b, m_bg_color.a));
if (nullptr == m_image_surface)
{
return;
}
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:
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:
SDL_BlitScaled(m_image_surface, nullptr, m_surface, nullptr);
break;
}
}
std::unique_ptr<Widget> WidgetImage::builder(const nlohmann::json& j)
{
int x = 0;
int y = 0;
int width = 0;
int height = 0;
string filename;
ImageResize resize_type = RESIZE_FIT;
HorizontalAlign halign = HALIGN_CENTER;
VerticalAlign valign = VALIGN_CENTER;
SDL_Color bg_color = {.r = 255, .g = 255, .b = 255, .a = SDL_ALPHA_TRANSPARENT};
json_extract(j, "x", x);
json_extract(j, "y", y);
json_extract(j, "width", width);
json_extract(j, "height", height);
json_extract(j, "filename", filename);
json_extract(j, "resize_type", resize_type);
json_extract(j, "halign", halign);
json_extract(j, "valign", valign);
json_extract(j, "bg_color", bg_color);
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;
}