129 lines
3.0 KiB
C++
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;
|
|
}
|