Compare commits
13 Commits
8e88adf1df
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 7c5cec7d8a | |||
| 3f4e42d7ce | |||
| 40df0f6e0c | |||
| 17f73211a9 | |||
| c626578557 | |||
| af9ebe5fe8 | |||
| 3d45fc89fc | |||
| 8e276ab2ab | |||
| ddc7898a78 | |||
| d0f538224b | |||
| 908ddeba44 | |||
| 82c35a6636 | |||
| 9f8a037f69 |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,4 +1,13 @@
|
|||||||
|
# Exclude the executable
|
||||||
trmnl_sdl
|
trmnl_sdl
|
||||||
|
|
||||||
|
# Exclude configuration files
|
||||||
*.json
|
*.json
|
||||||
|
|
||||||
|
# Exclude images
|
||||||
|
*.bmp
|
||||||
|
*.jpg
|
||||||
*.png
|
*.png
|
||||||
|
|
||||||
|
# Exclude fonts
|
||||||
*.ttf
|
*.ttf
|
||||||
|
|||||||
3
Makefile
3
Makefile
@@ -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
|
||||||
|
|||||||
121
README.md
121
README.md
@@ -1,19 +1,124 @@
|
|||||||
# What is this
|
# What is this
|
||||||
A utility which can be used to create custom images for TRMNL devices via code
|
A utility which can be used to create custom images for TRMNL devices via code
|
||||||
|
|
||||||
# How to write new visual stuff
|
# How to build
|
||||||
1. Inherit from `Widget` and then do your magic inside your own class.
|
**NOTE: Tested on Ubuntu 24.04.**
|
||||||
2. Add your widget builder in `main.cpp` inside `init_builders`.
|
|
||||||
3. Write your config file. Either named `config.json` or added as the first command line parameter.
|
|
||||||
4. ???
|
|
||||||
5. Profit
|
|
||||||
|
|
||||||
# ImageMagick commands
|
You will need the following packages: `build-essential` `libsdl2-dev` `libsdl2-image-dev` `libsdl2-ttf-dev` `imagemagick`
|
||||||
|
|
||||||
|
Just run `make` and an executable called `trmnl_sdl` should be produced.
|
||||||
|
|
||||||
|
# How to use
|
||||||
|
1. You will need to write a JSON config file.
|
||||||
|
It can either be named `config.json` or you will need to pass it as the first command line parameter to the executable.
|
||||||
|
An example structure of the config file can be found in `config_example.json`.
|
||||||
|
You can find more info on the available Widgets and their parameters at the end of this file.
|
||||||
|
2. Run the executable
|
||||||
|
3. Convert the image to a suitable format via an ImageMagick command from below.
|
||||||
|
|
||||||
|
# ImageMagick commands to prepare image for TRMNL device
|
||||||
### Convert image without dithering
|
### Convert image without dithering
|
||||||
`convert trmnl.png -monochrome -colors 2 -depth 1 -strip png:output.png`
|
`convert trmnl.png -monochrome -colors 2 -depth 1 -strip png:output.png`
|
||||||
|
|
||||||
### Convert image with dithering
|
### Convert image with dithering
|
||||||
`convert trmnl.png -dither FloydSteinberg -remap pattern:gray50 -depth 1 -strip png:output.png`
|
`convert trmnl.png -dither FloydSteinberg -remap pattern:gray50 -depth 1 -strip png:output.png`
|
||||||
|
|
||||||
|
### Resize image to fit with dithering
|
||||||
|
`convert image.png -resize 800x480 -background white -compose Copy -gravity center -extent 800x480 -dither FloydSteinberg -remap pattern:gray50 -depth 1 -strip png:output.png`
|
||||||
|
|
||||||
|
# How to write new visual stuff
|
||||||
|
1. Inherit from `Widget` and then do your magic inside your own class.
|
||||||
|
2. Add your widget builder in `main.cpp` inside `init_builders`.
|
||||||
|
3. Rebuild the executable.
|
||||||
|
|
||||||
# Notes
|
# Notes
|
||||||
json.hpp from nlohmann/json v3.11.2
|
json.hpp from [nlohmann/json](https://github.com/nlohmann/json) v3.11.2
|
||||||
|
|
||||||
|
# List of special types
|
||||||
|
### color
|
||||||
|
* **Object** type
|
||||||
|
* Components - Red, Green, Blue, Alpha
|
||||||
|
* Each component ranges 0-255
|
||||||
|
* When Alpha is 255 - the color is fully opaque. When it is 0 - fully transparent.
|
||||||
|
* Has the structure shown below:
|
||||||
|
```
|
||||||
|
"color": {
|
||||||
|
"r": 0,
|
||||||
|
"g": 0,
|
||||||
|
"b": 0,
|
||||||
|
"a": 255
|
||||||
|
}
|
||||||
|
```
|
||||||
|
**NOTE**: If only some components are present in the config then only the present ones are overwritten from the default.
|
||||||
|
|
||||||
|
### HAlign
|
||||||
|
Controls horizontal alignment of elements. **String** type. Has several options:
|
||||||
|
* left - Align objects to the left
|
||||||
|
* center - Align objects to be centered
|
||||||
|
* right - Align objects to the right
|
||||||
|
|
||||||
|
### VAlign
|
||||||
|
Controls vertical alignment of elements. **String** type. Has several options:
|
||||||
|
* top - Align objects to the top
|
||||||
|
* center - Align objects to be centered
|
||||||
|
* bottom - Align objects to the bottom
|
||||||
|
|
||||||
|
### ImageResize
|
||||||
|
Controls image resizing. **String** type. Has several options:
|
||||||
|
* none - Image is not resized and is only clipped by the bounding box
|
||||||
|
* fit - Image is uniformly scaled to fit inside the box
|
||||||
|
* stretch - Image is scaled (with possible stretching) to fully fill the box
|
||||||
|
|
||||||
|
### TextFit
|
||||||
|
Controls the automatic change of the text size depending on contents. **String** type. Has several options:
|
||||||
|
* none - Text is not changed in any way
|
||||||
|
* shrink - Renders text with desired size and shrinks it to fit if contents are too large
|
||||||
|
* auto - Renders text with desired size and enlarges/shrinks it to fit if contents are too small/large
|
||||||
|
|
||||||
|
# List of Widgets and their parameters
|
||||||
|
### image
|
||||||
|
Renders an image with optional scaling
|
||||||
|
| Name | Type | Required | Default | Description |
|
||||||
|
| ---: | :--: | :------: | ------: | :---------- |
|
||||||
|
| x | int | | 0 | Horizontal position in pixels (from left to right) |
|
||||||
|
| y | int | | 0 | Vertical position in pixels (from top to bottom) |
|
||||||
|
| width | int | REQ | | Width in pixels |
|
||||||
|
| height | int | REQ | | Height in pixels |
|
||||||
|
| filename | string | | | Filename of the image to render |
|
||||||
|
| resize_type | ImageResize | | fit | Whether to resize the image and how to do so |
|
||||||
|
| bg_color | color | | 255, 255, 255, 0 (Transparent WHITE) | The background color to fill around the image if it is not fully in the box |
|
||||||
|
| halign | HAlign | | center | Horizontal alignment of the image |
|
||||||
|
| valign | VAlign | | center | Vertical alignment of the image |
|
||||||
|
|
||||||
|
Supported image formats: **JPG**, **PNG**, **BMP**
|
||||||
|
|
||||||
|
### rect
|
||||||
|
Renders a rectangle with optional rounded corners using either fill or internal stroke.
|
||||||
|
| Name | Type | Required | Default | Description |
|
||||||
|
| ---: | :--: | :------: | ------: | :---------- |
|
||||||
|
| x | int | | 0 | Horizontal position in pixels (from left to right) |
|
||||||
|
| y | int | | 0 | Vertical position in pixels (from top to bottom) |
|
||||||
|
| width | int | REQ | | Width in pixels |
|
||||||
|
| height | int | REQ | | Height in pixels |
|
||||||
|
| radius | int | | 0 | Corner rounding radius in pixels |
|
||||||
|
| stroke | int | | -1 | Internal stroke size in pixels. If <= 0 then the rectangle will be filled with the desired color |
|
||||||
|
| color | color | | 0, 0, 0, 255 (BLACK) | Color to use for rectangle |
|
||||||
|
|
||||||
|
### text
|
||||||
|
Renders text within a specified box
|
||||||
|
| Name | Type | Required | Default | Description |
|
||||||
|
| ---: | :--: | :------: | ------: | :---------- |
|
||||||
|
| x | int | | 0 | Horizontal position in pixels (from left to right) |
|
||||||
|
| y | int | | 0 | Vertical position in pixels (from top to bottom) |
|
||||||
|
| width | int | REQ | | Max width in pixels |
|
||||||
|
| height | int | REQ | | Max height in pixels |
|
||||||
|
| text | string | | | The text to be shown |
|
||||||
|
| size | int | REQ | | Desired size of the text to use |
|
||||||
|
| font | string | | Global font key | Font file to use when rendering the text |
|
||||||
|
| color | color | | 0, 0, 0, 255 (BLACK) | Color to use for text rendering |
|
||||||
|
| should_wrap | boolean | | false | Whether the text should automatically wrap |
|
||||||
|
| fit | TextFit | | none | Controls automatic change the text size depending on contents |
|
||||||
|
| halign | HAlign | | center | Horizontal alignment of text |
|
||||||
|
| valign | VAlign | | center | Vertical alignment of text |
|
||||||
|
| halign_via_visible | boolean | | true | Whether to use visible pixels of the text for horizontal alignment. If false - uses text renderer hints |
|
||||||
|
| valign_via_visible | boolean | | true | Whether to use visible pixels of the text for vertical alignment. If false - uses text renderer hints |
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include "../json.hpp"
|
#include "../json.hpp"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
// Base Widget class for the whole Widget system
|
||||||
class Widget
|
class Widget
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
165
Widgets/WidgetImage.cpp
Normal file
165
Widgets/WidgetImage.cpp
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
#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::set_filename(const string& filename)
|
||||||
|
{
|
||||||
|
if (m_image_surface != nullptr)
|
||||||
|
{
|
||||||
|
SDL_FreeSurface(m_image_surface);
|
||||||
|
m_image_surface = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_filename = filename;
|
||||||
|
m_image_surface = IMG_Load(m_filename.c_str());
|
||||||
|
if (nullptr == m_image_surface)
|
||||||
|
{
|
||||||
|
// TODO: Print errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetImage::set_resize(ImageResize type)
|
||||||
|
{
|
||||||
|
m_resize_type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetImage::set_halign(HorizontalAlign halign)
|
||||||
|
{
|
||||||
|
m_halign = halign;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetImage::set_valign(VerticalAlign valign)
|
||||||
|
{
|
||||||
|
m_valign = valign;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetImage::set_bg_color(SDL_Color bg_color)
|
||||||
|
{
|
||||||
|
m_bg_color = bg_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
59
Widgets/WidgetImage.h
Normal file
59
Widgets/WidgetImage.h
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#ifndef WIDGET_IMAGE_H_
|
||||||
|
#define WIDGET_IMAGE_H_
|
||||||
|
|
||||||
|
#include "Widget.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "../sdl_helpers.h"
|
||||||
|
|
||||||
|
// Renders an image with optional scaling
|
||||||
|
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});
|
||||||
|
|
||||||
|
void set_filename(const std::string& filename);
|
||||||
|
void set_resize(ImageResize type);
|
||||||
|
void set_halign(HorizontalAlign halign);
|
||||||
|
void set_valign(VerticalAlign valign);
|
||||||
|
void set_bg_color(SDL_Color bg_color);
|
||||||
|
|
||||||
|
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_
|
||||||
@@ -24,8 +24,28 @@ m_radius(radius)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WidgetRect::set_color(SDL_Color color)
|
||||||
|
{
|
||||||
|
m_color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetRect::set_stroke_size(int stroke_size)
|
||||||
|
{
|
||||||
|
m_stroke_size = stroke_size
|
||||||
|
}
|
||||||
|
|
||||||
|
void WidgetRect::set_radius(int radius)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
|
||||||
@@ -97,7 +117,7 @@ void WidgetRect::draw()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget* WidgetRect::builder(const nlohmann::json& j)
|
std::unique_ptr<Widget> WidgetRect::builder(const nlohmann::json& j)
|
||||||
{
|
{
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
@@ -115,7 +135,7 @@ Widget* WidgetRect::builder(const nlohmann::json& j)
|
|||||||
json_extract(j, "stroke", stroke_size);
|
json_extract(j, "stroke", stroke_size);
|
||||||
json_extract(j, "color", color);
|
json_extract(j, "color", color);
|
||||||
|
|
||||||
return new WidgetRect(x, y, width, height, radius, stroke_size, color);
|
return std::make_unique<WidgetRect>(x, y, width, height, radius, stroke_size, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WidgetRect::draw_circle_corner(int x, int y, int quadrant)
|
void WidgetRect::draw_circle_corner(int x, int y, int quadrant)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "Widget.h"
|
#include "Widget.h"
|
||||||
|
|
||||||
|
// Renders a rectangle with optional rounded corners using either fill or internal stroke
|
||||||
class WidgetRect : public Widget
|
class WidgetRect : public Widget
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@@ -26,11 +27,15 @@ public:
|
|||||||
WidgetRect(int x, int y, int width, int height,
|
WidgetRect(int x, int y, int width, int height,
|
||||||
int radius = 0, int stroke_size = -1);
|
int radius = 0, int stroke_size = -1);
|
||||||
|
|
||||||
|
void set_color(SDL_Color color);
|
||||||
|
void set_stroke_size(int stroke_size);
|
||||||
|
void set_radius(int radius);
|
||||||
|
|
||||||
virtual void draw() override;
|
virtual void draw() override;
|
||||||
|
|
||||||
static 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);
|
||||||
|
|||||||
@@ -15,9 +15,76 @@ static SDL_Surface* render_text(bool should_wrap, TTF_Font* font, const string&
|
|||||||
return txt_surface;
|
return txt_surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SDL_Rect find_visible_area(const SDL_Surface* txt_surface)
|
||||||
|
{
|
||||||
|
int x_start = -1;
|
||||||
|
int x_end = -1;
|
||||||
|
int y_start = -1;
|
||||||
|
int y_end = -1;
|
||||||
|
|
||||||
|
for (int y = 0; y < txt_surface->h; ++y)
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
|
for (int x = 0; x < txt_surface->w; ++x)
|
||||||
|
{
|
||||||
|
if (1 == (static_cast<Uint8*>(txt_surface->pixels)[y * txt_surface->pitch + x]))
|
||||||
|
{
|
||||||
|
if (-1 == x_start)
|
||||||
|
{
|
||||||
|
x_start = x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (x < x_start)
|
||||||
|
{
|
||||||
|
x_start = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-1 == x_end)
|
||||||
|
{
|
||||||
|
x_end = x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (x > x_end)
|
||||||
|
{
|
||||||
|
x_end = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
if (-1 == y_start)
|
||||||
|
{
|
||||||
|
y_start = y;
|
||||||
|
}
|
||||||
|
y_end = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SDL_Rect result = {.x = 0, .y = 0, .w = 0, .h = 0};
|
||||||
|
if ((-1 != x_start) && (-1 != x_end))
|
||||||
|
{
|
||||||
|
result.x = x_start;
|
||||||
|
result.w = x_end - x_start + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((-1 != y_start) && (-1 != y_end))
|
||||||
|
{
|
||||||
|
result.y = y_start;
|
||||||
|
result.h = y_end - y_start + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
WidgetText::WidgetText(int x, int y, int width, int height, string text,
|
WidgetText::WidgetText(int x, int y, int width, int height, string text,
|
||||||
TextFit fit, bool should_wrap,
|
TextFit fit, bool should_wrap,
|
||||||
HorizontalAlign halign, VerticalAlign valign,
|
HorizontalAlign halign, VerticalAlign valign,
|
||||||
|
bool halign_via_visible, bool valign_via_visible,
|
||||||
SDL_Color text_color,
|
SDL_Color text_color,
|
||||||
int size, std::string font)
|
int size, std::string font)
|
||||||
: Widget(x, y, width, height),
|
: Widget(x, y, width, height),
|
||||||
@@ -28,7 +95,9 @@ m_fit(fit),
|
|||||||
m_should_wrap(should_wrap),
|
m_should_wrap(should_wrap),
|
||||||
m_halign(halign),
|
m_halign(halign),
|
||||||
m_valign(valign),
|
m_valign(valign),
|
||||||
m_text_color(text_color)
|
m_text_color(text_color),
|
||||||
|
m_halign_via_visible(halign_via_visible),
|
||||||
|
m_valign_via_visible(valign_via_visible)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +112,9 @@ m_fit(fit),
|
|||||||
m_should_wrap(should_wrap),
|
m_should_wrap(should_wrap),
|
||||||
m_halign(HALIGN_CENTER),
|
m_halign(HALIGN_CENTER),
|
||||||
m_valign(VALIGN_CENTER),
|
m_valign(VALIGN_CENTER),
|
||||||
m_text_color{.r = 0, .g = 0, .b = 0, .a = SDL_ALPHA_OPAQUE}
|
m_text_color{.r = 0, .g = 0, .b = 0, .a = SDL_ALPHA_OPAQUE},
|
||||||
|
m_halign_via_visible(true),
|
||||||
|
m_valign_via_visible(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +127,9 @@ m_size(size),
|
|||||||
m_fit(FIT_NONE),
|
m_fit(FIT_NONE),
|
||||||
m_halign(HALIGN_CENTER),
|
m_halign(HALIGN_CENTER),
|
||||||
m_valign(VALIGN_CENTER),
|
m_valign(VALIGN_CENTER),
|
||||||
m_text_color{.r = 0, .g = 0, .b = 0, .a = SDL_ALPHA_OPAQUE}
|
m_text_color{.r = 0, .g = 0, .b = 0, .a = SDL_ALPHA_OPAQUE},
|
||||||
|
m_halign_via_visible(true),
|
||||||
|
m_valign_via_visible(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,8 +168,22 @@ void WidgetText::set_color(SDL_Color text_color)
|
|||||||
m_text_color = text_color;
|
m_text_color = text_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WidgetText::set_halign_via_visible(bool value)
|
||||||
|
{
|
||||||
|
m_halign_via_visible = value;
|
||||||
|
}
|
||||||
|
void WidgetText::set_valign_via_visible(bool value)
|
||||||
|
{
|
||||||
|
m_valign_via_visible = value;
|
||||||
|
}
|
||||||
|
|
||||||
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));
|
||||||
|
|
||||||
@@ -171,12 +258,25 @@ void WidgetText::draw()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now we have the final rendered text surface
|
// Now we have the final rendered text surface
|
||||||
SDL_Rect align = surface_align(m_surface, txt_surface, m_halign, m_valign);
|
SDL_Rect hint = find_visible_area(txt_surface);
|
||||||
|
if (!m_halign_via_visible)
|
||||||
|
{
|
||||||
|
hint.x = 0;
|
||||||
|
hint.w = txt_surface->w;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_valign_via_visible)
|
||||||
|
{
|
||||||
|
hint.y = 0;
|
||||||
|
hint.h = txt_surface->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Rect align = surface_align(m_surface, txt_surface, m_halign, m_valign, &hint);
|
||||||
SDL_BlitSurface(txt_surface, NULL, m_surface, &align);
|
SDL_BlitSurface(txt_surface, NULL, m_surface, &align);
|
||||||
SDL_FreeSurface(txt_surface);
|
SDL_FreeSurface(txt_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget* WidgetText::builder(const nlohmann::json& j)
|
std::unique_ptr<Widget> WidgetText::builder(const nlohmann::json& j)
|
||||||
{
|
{
|
||||||
int x = 0;
|
int x = 0;
|
||||||
int y = 0;
|
int y = 0;
|
||||||
@@ -187,6 +287,8 @@ Widget* WidgetText::builder(const nlohmann::json& j)
|
|||||||
bool should_wrap = false;
|
bool should_wrap = false;
|
||||||
HorizontalAlign halign = HALIGN_CENTER;
|
HorizontalAlign halign = HALIGN_CENTER;
|
||||||
VerticalAlign valign = VALIGN_CENTER;
|
VerticalAlign valign = VALIGN_CENTER;
|
||||||
|
bool halign_via_visible = true;
|
||||||
|
bool valign_via_visible = true;
|
||||||
SDL_Color text_color = {.r = 0, .g = 0, .b = 0, .a = SDL_ALPHA_OPAQUE};
|
SDL_Color text_color = {.r = 0, .g = 0, .b = 0, .a = SDL_ALPHA_OPAQUE};
|
||||||
int size = 0;
|
int size = 0;
|
||||||
string font = "";
|
string font = "";
|
||||||
@@ -200,6 +302,8 @@ Widget* WidgetText::builder(const nlohmann::json& j)
|
|||||||
json_extract(j, "should_wrap", should_wrap);
|
json_extract(j, "should_wrap", should_wrap);
|
||||||
json_extract(j, "halign", halign);
|
json_extract(j, "halign", halign);
|
||||||
json_extract(j, "valign", valign);
|
json_extract(j, "valign", valign);
|
||||||
|
json_extract(j, "halign_via_visible", halign_via_visible);
|
||||||
|
json_extract(j, "valign_via_visible", valign_via_visible);
|
||||||
json_extract(j, "color", text_color);
|
json_extract(j, "color", text_color);
|
||||||
json_extract(j, "size", size);
|
json_extract(j, "size", size);
|
||||||
json_extract(j, "font", font);
|
json_extract(j, "font", font);
|
||||||
@@ -209,5 +313,9 @@ Widget* WidgetText::builder(const nlohmann::json& j)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new WidgetText(x, y, width, height, text, fit, should_wrap, halign, valign, text_color, size, font);
|
return std::make_unique<WidgetText>(x, y, width, height,
|
||||||
|
text, fit, should_wrap,
|
||||||
|
halign, valign,
|
||||||
|
halign_via_visible, valign_via_visible,
|
||||||
|
text_color, size, font);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
#define WIDGET_TEXT_H_
|
#define WIDGET_TEXT_H_
|
||||||
|
|
||||||
#include "Widget.h"
|
#include "Widget.h"
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "../sdl_helpers.h"
|
#include "../sdl_helpers.h"
|
||||||
|
|
||||||
|
// Renders text within a specified box
|
||||||
class WidgetText : public Widget
|
class WidgetText : public Widget
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@@ -40,10 +40,19 @@ protected:
|
|||||||
// Default - black
|
// Default - black
|
||||||
SDL_Color m_text_color;
|
SDL_Color m_text_color;
|
||||||
|
|
||||||
|
// Whether to H-align via visible pixels or rendering surface
|
||||||
|
// Default - true
|
||||||
|
bool m_halign_via_visible;
|
||||||
|
|
||||||
|
// Whether to V-align via visible pixels or rendering surface
|
||||||
|
// Default - true
|
||||||
|
bool m_valign_via_visible;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
WidgetText(int x, int y, int width, int height, std::string text,
|
WidgetText(int x, int y, int width, int height, std::string text,
|
||||||
TextFit fit, bool should_wrap,
|
TextFit fit, bool should_wrap,
|
||||||
HorizontalAlign halign, VerticalAlign valign,
|
HorizontalAlign halign, VerticalAlign valign,
|
||||||
|
bool halign_via_visible, bool valign_via_visible,
|
||||||
SDL_Color text_color,
|
SDL_Color text_color,
|
||||||
int size, std::string font = "");
|
int size, std::string font = "");
|
||||||
|
|
||||||
@@ -61,10 +70,12 @@ public:
|
|||||||
void set_halign(HorizontalAlign halign);
|
void set_halign(HorizontalAlign halign);
|
||||||
void set_valign(VerticalAlign valign);
|
void set_valign(VerticalAlign valign);
|
||||||
void set_color(SDL_Color text_color);
|
void set_color(SDL_Color text_color);
|
||||||
|
void set_halign_via_visible(bool value);
|
||||||
|
void set_valign_via_visible(bool value);
|
||||||
|
|
||||||
virtual void draw() override;
|
virtual void draw() override;
|
||||||
|
|
||||||
static Widget* builder(const nlohmann::json& j);
|
static std::unique_ptr<Widget> builder(const nlohmann::json& j);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // WIDGET_TEXT_H_
|
#endif // WIDGET_TEXT_H_
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"width": 800,
|
"width": 800,
|
||||||
"height": 600,
|
"height": 480,
|
||||||
"output": "trmnl.png",
|
"output": "trmnl.png",
|
||||||
"font": "font.ttf",
|
"font": "font.ttf",
|
||||||
"widgets":
|
"widgets":
|
||||||
|
|||||||
26
main.cpp
26
main.cpp
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -11,20 +12,24 @@
|
|||||||
|
|
||||||
#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;
|
||||||
using std::map;
|
using std::map;
|
||||||
|
using std::shared_ptr;
|
||||||
using std::string;
|
using std::string;
|
||||||
|
using std::unique_ptr;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
|
||||||
void init_builders(map<string, Widget*(*)(const json&)>& widget_builders)
|
void init_builders(map<string, unique_ptr<Widget>(*)(const json&)>& widget_builders)
|
||||||
{
|
{
|
||||||
widget_builders["text"] = &WidgetText::builder;
|
widget_builders["image"] = &WidgetImage::builder;
|
||||||
widget_builders["rect"] = &WidgetRect::builder;
|
widget_builders["rect"] = &WidgetRect::builder;
|
||||||
|
widget_builders["text"] = &WidgetText::builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
@@ -33,7 +38,7 @@ int main(int argc, char **argv)
|
|||||||
bool ok;
|
bool ok;
|
||||||
|
|
||||||
int screen_width = 800;
|
int screen_width = 800;
|
||||||
int screen_height = 600;
|
int screen_height = 480;
|
||||||
string output_filename = "trmnl.png";
|
string output_filename = "trmnl.png";
|
||||||
string cfg_filename = "config.json";
|
string cfg_filename = "config.json";
|
||||||
json cfg;
|
json cfg;
|
||||||
@@ -41,8 +46,8 @@ int main(int argc, char **argv)
|
|||||||
SDL_Surface* main_surface = nullptr;
|
SDL_Surface* main_surface = nullptr;
|
||||||
|
|
||||||
vector<json> widgets_cfg;
|
vector<json> widgets_cfg;
|
||||||
vector<Widget*> widgets;
|
vector<shared_ptr<Widget>> widgets;
|
||||||
map<string, Widget*(*)(const json&)> widget_builders;
|
map<string, unique_ptr<Widget>(*)(const json&)> widget_builders;
|
||||||
|
|
||||||
ok = init_sdl();
|
ok = init_sdl();
|
||||||
if (!ok)
|
if (!ok)
|
||||||
@@ -102,7 +107,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Construct and add widget to vector
|
// Construct and add widget to vector
|
||||||
Widget* widget = widget_builders[widget_name](j);
|
shared_ptr<Widget> widget = widget_builders[widget_name](j);
|
||||||
if (nullptr != widget)
|
if (nullptr != widget)
|
||||||
{
|
{
|
||||||
widgets.push_back(widget);
|
widgets.push_back(widget);
|
||||||
@@ -113,7 +118,7 @@ int main(int argc, char **argv)
|
|||||||
SDL_FillRect(main_surface, nullptr, SDL_MapRGBA(main_surface->format, 255, 255, 255, SDL_ALPHA_OPAQUE));
|
SDL_FillRect(main_surface, nullptr, SDL_MapRGBA(main_surface->format, 255, 255, 255, SDL_ALPHA_OPAQUE));
|
||||||
|
|
||||||
// Draw and apply all widgets
|
// Draw and apply all widgets
|
||||||
for (Widget* widget : widgets)
|
for (shared_ptr<Widget>& widget : widgets)
|
||||||
{
|
{
|
||||||
widget->draw();
|
widget->draw();
|
||||||
SDL_Rect rect = widget->get_rect();
|
SDL_Rect rect = widget->get_rect();
|
||||||
@@ -125,11 +130,6 @@ int main(int argc, char **argv)
|
|||||||
IMG_SavePNG(main_surface, output_filename.c_str());
|
IMG_SavePNG(main_surface, output_filename.c_str());
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
// Destroy All Widgets
|
|
||||||
for (Widget* widget : widgets)
|
|
||||||
{
|
|
||||||
delete widget;
|
|
||||||
}
|
|
||||||
widgets.clear();
|
widgets.clear();
|
||||||
|
|
||||||
clean_sdl();
|
clean_sdl();
|
||||||
|
|||||||
@@ -77,42 +77,56 @@ TTF_Font* get_font(int size, const string& filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SDL_Rect surface_align(const SDL_Surface* base, const SDL_Surface* applied,
|
SDL_Rect surface_align(const SDL_Surface* base, const SDL_Surface* applied,
|
||||||
HorizontalAlign halign, VerticalAlign valign)
|
HorizontalAlign halign, VerticalAlign valign, const SDL_Rect* hint_external)
|
||||||
{
|
{
|
||||||
SDL_Rect align = {.x = 0, .y = 0, .w = 0, .h = 0};
|
SDL_Rect align = {.x = 0, .y = 0, .w = 0, .h = 0};
|
||||||
|
SDL_Rect hint;
|
||||||
|
|
||||||
if ((nullptr == base) || (nullptr == applied))
|
if ((nullptr == base) || (nullptr == 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)
|
||||||
|
{
|
||||||
|
hint = SDL_Rect{.x = 0, .y = 0, .w = applied->w, .h = applied->h};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hint = *hint_external;
|
||||||
|
}
|
||||||
|
|
||||||
switch (halign)
|
switch (halign)
|
||||||
{
|
{
|
||||||
case HALIGN_LEFT:
|
case HALIGN_LEFT:
|
||||||
align.x = 0;
|
align.x = -hint.x;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HALIGN_CENTER:
|
case HALIGN_CENTER:
|
||||||
align.x = base->w / 2 - applied->w / 2;
|
align.x = base->w / 2 - hint.x - hint.w / 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HALIGN_RIGHT:
|
case HALIGN_RIGHT:
|
||||||
align.x = base->w - applied->w;
|
align.x = base->w - (hint.x + hint.w);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (valign)
|
switch (valign)
|
||||||
{
|
{
|
||||||
case VALIGN_TOP:
|
case VALIGN_TOP:
|
||||||
align.y = 0;
|
align.y = -hint.y;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VALIGN_CENTER:
|
case VALIGN_CENTER:
|
||||||
align.y = base->h / 2 - applied->h / 2;
|
align.y = base->h / 2 - hint.y - hint.h / 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VALIGN_BOTTOM:
|
case VALIGN_BOTTOM:
|
||||||
align.y = base->h - applied->h;
|
align.y = base->h - (hint.y + hint.h);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,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())
|
||||||
{
|
{
|
||||||
@@ -165,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())
|
||||||
{
|
{
|
||||||
@@ -228,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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
@@ -66,8 +80,9 @@ TTF_Font* get_font(int size, const std::string& filename = default_font_name);
|
|||||||
// Returns a rect to use during bliting of 2 surfaces
|
// Returns a rect to use during bliting of 2 surfaces
|
||||||
// base - surface on which the other is applied to
|
// base - surface on which the other is applied to
|
||||||
// applied - the surface which will be applied to the other
|
// applied - the surface which will be applied to the other
|
||||||
|
// hint - rect to hint visible area from applied - can be NULL
|
||||||
SDL_Rect surface_align(const SDL_Surface* base, const SDL_Surface* applied,
|
SDL_Rect surface_align(const SDL_Surface* base, const SDL_Surface* applied,
|
||||||
HorizontalAlign halign, VerticalAlign valign);
|
HorizontalAlign halign, VerticalAlign valign, const SDL_Rect* hint = nullptr);
|
||||||
|
|
||||||
// Reads the file and tries to parse a JSON file with comments
|
// Reads the file and tries to parse a JSON file with comments
|
||||||
// cfg - output json struct
|
// cfg - output json struct
|
||||||
@@ -85,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_
|
||||||
|
|||||||
Reference in New Issue
Block a user