Compare commits

..

3 Commits

10 changed files with 232 additions and 7 deletions

View File

@ -2,8 +2,9 @@ src_files += main.cpp
src_files += sdl_helpers.cpp src_files += sdl_helpers.cpp
src_files += Widgets/Widget.cpp src_files += Widgets/Widget.cpp
src_files += Widgets/WidgetText.cpp src_files += Widgets/WidgetImage.cpp
src_files += Widgets/WidgetRect.cpp src_files += Widgets/WidgetRect.cpp
src_files += Widgets/WidgetText.cpp
all: all:
g++ $(src_files) -Wall -lSDL2 -lSDL2_ttf -lSDL2_image -o trmnl_sdl g++ $(src_files) -Wall -lSDL2 -lSDL2_ttf -lSDL2_image -o trmnl_sdl

128
Widgets/WidgetImage.cpp Normal file
View File

@ -0,0 +1,128 @@
#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;
}

52
Widgets/WidgetImage.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef WIDGET_IMAGE_H_
#define WIDGET_IMAGE_H_
#include "Widget.h"
#include <string>
#include "../sdl_helpers.h"
class WidgetImage : public Widget
{
protected:
// Image filepath
std::string m_filename;
// Image surface
SDL_Surface* m_image_surface;
// Whether to resize the image and how
// RESIZE_NONE - Do not resize
// RESIZE_FIT - Scale the image to fit the rectangle
// RESIZE_STRETCH - Scale and stretch the image to fit the box perfectly
ImageResize m_resize_type;
// Default - center
HorizontalAlign m_halign;
// Default - center
VerticalAlign m_valign;
// Background color to be used
// Default - transparent white
SDL_Color m_bg_color;
public:
WidgetImage(int x, int y, int width, int height, std::string filename,
ImageResize resize_type = RESIZE_FIT,
HorizontalAlign halign = HALIGN_CENTER,
VerticalAlign valign = VALIGN_CENTER,
SDL_Color bg_color = SDL_Color{.r = 255, .g = 255, .b = 255, .a = SDL_ALPHA_TRANSPARENT});
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

@ -26,6 +26,11 @@ m_radius(radius)
void WidgetRect::draw() void WidgetRect::draw()
{ {
if (nullptr == m_surface)
{
return;
}
// Clear surface // Clear surface
SDL_FillRect(m_surface, nullptr, SDL_MapRGBA(m_surface->format, 255, 255, 255, SDL_ALPHA_TRANSPARENT)); SDL_FillRect(m_surface, nullptr, SDL_MapRGBA(m_surface->format, 255, 255, 255, SDL_ALPHA_TRANSPARENT));

View File

@ -31,7 +31,7 @@ public:
static std::unique_ptr<Widget> builder(const nlohmann::json& j); static std::unique_ptr<Widget> builder(const nlohmann::json& j);
private: protected:
// x, y - center of circle // x, y - center of circle
// quadrant - 1--4 // quadrant - 1--4
void draw_circle_corner(int x, int y, int quadrant); void draw_circle_corner(int x, int y, int quadrant);

View File

@ -170,6 +170,11 @@ void WidgetText::set_color(SDL_Color text_color)
void WidgetText::draw() void WidgetText::draw()
{ {
if (nullptr == m_surface)
{
return;
}
// Clear surface // Clear surface
SDL_FillRect(m_surface, nullptr, SDL_MapRGBA(m_surface->format, 255, 255, 255, SDL_ALPHA_TRANSPARENT)); SDL_FillRect(m_surface, nullptr, SDL_MapRGBA(m_surface->format, 255, 255, 255, SDL_ALPHA_TRANSPARENT));

View File

@ -2,7 +2,6 @@
#define WIDGET_TEXT_H_ #define WIDGET_TEXT_H_
#include "Widget.h" #include "Widget.h"
#include <SDL2/SDL.h>
#include <string> #include <string>

View File

@ -12,8 +12,9 @@
#include "sdl_helpers.h" #include "sdl_helpers.h"
#include "Widgets/Widget.h" #include "Widgets/Widget.h"
#include "Widgets/WidgetText.h" #include "Widgets/WidgetImage.h"
#include "Widgets/WidgetRect.h" #include "Widgets/WidgetRect.h"
#include "Widgets/WidgetText.h"
using std::cout; using std::cout;
using std::endl; using std::endl;
@ -26,6 +27,7 @@ using nlohmann::json;
void init_builders(map<string, unique_ptr<Widget>(*)(const json&)>& widget_builders) void init_builders(map<string, unique_ptr<Widget>(*)(const json&)>& widget_builders)
{ {
widget_builders["image"] = &WidgetImage::builder;
widget_builders["rect"] = &WidgetRect::builder; widget_builders["rect"] = &WidgetRect::builder;
widget_builders["text"] = &WidgetText::builder; widget_builders["text"] = &WidgetText::builder;
} }

View File

@ -87,6 +87,10 @@ SDL_Rect surface_align(const SDL_Surface* base, const SDL_Surface* applied,
return align; return align;
} }
// These are set in order to handle scaled blits
align.w = applied->w;
align.h = applied->h;
if (nullptr == hint_external) if (nullptr == hint_external)
{ {
hint = SDL_Rect{.x = 0, .y = 0, .w = applied->w, .h = applied->h}; hint = SDL_Rect{.x = 0, .y = 0, .w = applied->w, .h = applied->h};
@ -167,7 +171,7 @@ void json_extract(const json& j, const string& key, string& out)
} }
} }
void json_extract(const nlohmann::json& j, const string& key, int& out) void json_extract(const json& j, const string& key, int& out)
{ {
if (j.contains(key) && j[key].is_number_integer()) if (j.contains(key) && j[key].is_number_integer())
{ {
@ -175,7 +179,7 @@ void json_extract(const nlohmann::json& j, const string& key, int& out)
} }
} }
void json_extract(const nlohmann::json& j, const string& key, bool& out) void json_extract(const json& j, const string& key, bool& out)
{ {
if (j.contains(key) && j[key].is_boolean()) if (j.contains(key) && j[key].is_boolean())
{ {
@ -238,10 +242,24 @@ void json_extract(const json& j, const string& key, SDL_Color& out)
} }
} }
void json_extract(const nlohmann::json& j, const string& key, Uint8& out) void json_extract(const json& j, const string& key, Uint8& out)
{ {
if (j.contains(key) && j[key].is_number_unsigned()) if (j.contains(key) && j[key].is_number_unsigned())
{ {
out = j[key]; out = j[key];
} }
} }
void json_extract(const json& j, const string& key, ImageResize& out)
{
if (j.contains(key))
{
try
{
out = j[key].get<ImageResize>();
}
catch(const std::exception& e)
{
}
}
}

View File

@ -52,6 +52,20 @@ NLOHMANN_JSON_SERIALIZE_ENUM(TextFit,
{FIT_AUTO, "auto"}, {FIT_AUTO, "auto"},
}) })
enum ImageResize
{
RESIZE_NONE,
RESIZE_FIT,
RESIZE_STRETCH
};
NLOHMANN_JSON_SERIALIZE_ENUM(ImageResize,
{
{RESIZE_NONE, "none"},
{RESIZE_FIT, "fit"},
{RESIZE_STRETCH, "stretch"},
})
// Call this before everything // Call this before everything
// Prints its messages // Prints its messages
bool init_sdl(); bool init_sdl();
@ -86,5 +100,6 @@ void json_extract(const nlohmann::json& j, const std::string& key, VerticalAlign
void json_extract(const nlohmann::json& j, const std::string& key, TextFit& out); void json_extract(const nlohmann::json& j, const std::string& key, TextFit& out);
void json_extract(const nlohmann::json& j, const std::string& key, SDL_Color& out); void json_extract(const nlohmann::json& j, const std::string& key, SDL_Color& out);
void json_extract(const nlohmann::json& j, const std::string& key, Uint8& out); void json_extract(const nlohmann::json& j, const std::string& key, Uint8& out);
void json_extract(const nlohmann::json& j, const std::string& key, ImageResize& out);
#endif // SDL_HELPERS_H_ #endif // SDL_HELPERS_H_