Added WidgetRect to draw rectangles

This commit is contained in:
nedko 2025-12-08 15:33:19 +02:00
parent 3a52a3991c
commit 8e88adf1df
4 changed files with 246 additions and 0 deletions

View File

@ -3,6 +3,7 @@ src_files += sdl_helpers.cpp
src_files += Widgets/Widget.cpp src_files += Widgets/Widget.cpp
src_files += Widgets/WidgetText.cpp src_files += Widgets/WidgetText.cpp
src_files += Widgets/WidgetRect.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

204
Widgets/WidgetRect.cpp Normal file
View File

@ -0,0 +1,204 @@
#include "WidgetRect.h"
#include <vector>
#include "../sdl_helpers.h"
using std::vector;
WidgetRect::WidgetRect(int x, int y, int width, int height,
int radius, int stroke_size, SDL_Color color)
: Widget(x, y, width, height),
m_color(color),
m_stroke_size(stroke_size),
m_radius(radius)
{
}
WidgetRect::WidgetRect(int x, int y, int width, int height,
int radius, int stroke_size)
: Widget(x, y, width, height),
m_color{.r = 0, .g = 0, .b = 0, .a = SDL_ALPHA_OPAQUE},
m_stroke_size(stroke_size),
m_radius(radius)
{
}
void WidgetRect::draw()
{
// Clear surface
SDL_FillRect(m_surface, nullptr, SDL_MapRGBA(m_surface->format, 255, 255, 255, SDL_ALPHA_TRANSPARENT));
if (m_radius > 0)
{
// Draw rounded corners here
draw_circle_corner(m_rect.w - m_radius, m_radius - 1, 1);
draw_circle_corner(m_radius - 1, m_radius - 1, 2);
draw_circle_corner(m_radius - 1, m_rect.h - m_radius, 3);
draw_circle_corner(m_rect.w - m_radius, m_rect.h - m_radius, 4);
// Draw X rect
if (m_radius * 2 < m_rect.w)
{
SDL_Rect rect;
rect.x = 0;
rect.y = m_radius;
rect.w = m_rect.w;
rect.h = m_rect.h - 2 * m_radius;
SDL_FillRect(m_surface, &rect, SDL_MapRGBA(m_surface->format, m_color.r, m_color.g, m_color.b, m_color.a));
if (m_stroke_size > 0)
{
rect.x = m_stroke_size;
rect.y = m_radius;
rect.w = m_rect.w - 2 * m_stroke_size;
rect.h = m_rect.h - 2 * m_radius;
SDL_FillRect(m_surface, &rect, SDL_MapRGBA(m_surface->format, 255, 255, 255, SDL_ALPHA_TRANSPARENT));
}
}
// Draw Y rect
if (m_radius * 2 < m_rect.h)
{
SDL_Rect rect;
rect.x = m_radius;
rect.y = 0;
rect.w = m_rect.w - 2 * m_radius;
rect.h = m_rect.h;
SDL_FillRect(m_surface, &rect, SDL_MapRGBA(m_surface->format, m_color.r, m_color.g, m_color.b, m_color.a));
if (m_stroke_size > 0)
{
rect.x = m_radius;
rect.y = m_stroke_size;
rect.w = m_rect.w - 2 * m_radius;
rect.h = m_rect.h - 2 * m_stroke_size;
SDL_FillRect(m_surface, &rect, SDL_MapRGBA(m_surface->format, 255, 255, 255, SDL_ALPHA_TRANSPARENT));
}
}
}
else
{
SDL_Rect rect;
rect.x = 0;
rect.y = 0;
rect.w = m_rect.w;
rect.h = m_rect.h;
SDL_FillRect(m_surface, &rect, SDL_MapRGBA(m_surface->format, m_color.r, m_color.g, m_color.b, m_color.a));
if (m_stroke_size > 0)
{
rect.x = m_stroke_size;
rect.y = m_stroke_size;
rect.w = m_rect.w - 2 * m_stroke_size;
rect.h = m_rect.h - 2 * m_stroke_size;
SDL_FillRect(m_surface, &rect, SDL_MapRGBA(m_surface->format, 255, 255, 255, SDL_ALPHA_TRANSPARENT));
}
}
}
Widget* WidgetRect::builder(const nlohmann::json& j)
{
int x = 0;
int y = 0;
int width = 0;
int height = 0;
int radius = 0;
int stroke_size = -1;
SDL_Color color = {.r = 0, .g = 0, .b = 0, .a = SDL_ALPHA_OPAQUE};
json_extract(j, "x", x);
json_extract(j, "y", y);
json_extract(j, "width", width);
json_extract(j, "height", height);
json_extract(j, "radius", radius);
json_extract(j, "stroke", stroke_size);
json_extract(j, "color", color);
return new WidgetRect(x, y, width, height, radius, stroke_size, color);
}
void WidgetRect::draw_circle_corner(int x, int y, int quadrant)
{
if (0 == m_radius)
{
return;
}
int x_add;
int y_add;
switch (quadrant)
{
case 1:
x_add = 1;
y_add = -1;
break;
case 2:
x_add = -1;
y_add = -1;
break;
case 3:
x_add = -1;
y_add = 1;
break;
case 4:
x_add = 1;
y_add = 1;
break;
default:
// TODO: Message printing
return;
break;
}
// Create renderer
SDL_Renderer* renderer = SDL_CreateSoftwareRenderer(m_surface);
if (nullptr == renderer)
{
// TODO: Message printing
return;
}
SDL_SetRenderDrawColor(renderer, m_color.r, m_color.g, m_color.b, m_color.a);
vector<SDL_Point> points;
int max_dist = m_radius * m_radius;
int min_dist = 0;
if (m_stroke_size > 0)
{
min_dist = (m_radius - m_stroke_size) * (m_radius - m_stroke_size);
}
for (int i_x = 0; i_x < m_radius; ++i_x)
for (int i_y = 0; i_y < m_radius; ++i_y)
{
bool should_fill = false;
// a2 + b2 = c2
int dist = i_x * i_x + i_y * i_y;
// <= c2 (max) && > c2 (min)
if ((dist <= max_dist) && (dist >= min_dist))
{
should_fill = true;
}
if (should_fill)
{
SDL_Point point =
{
.x = x + x_add * i_x,
.y = y + y_add * i_y
};
points.push_back(point);
}
}
SDL_RenderDrawPoints(renderer, points.data(), points.size());
SDL_DestroyRenderer(renderer);
}

39
Widgets/WidgetRect.h Normal file
View File

@ -0,0 +1,39 @@
#ifndef WIDGET_RECT_H_
#define WIDGET_RECT_H_
#include "Widget.h"
class WidgetRect : public Widget
{
protected:
// The color of the rectangle
// Default - Black (0, 0, 0)
SDL_Color m_color;
// Size of the internal stroke
// Set to -1 to fill the space
// Default - -1
int m_stroke_size;
// Corner rounding radius
// Default - 0;
int m_radius;
public:
WidgetRect(int x, int y, int width, int height,
int radius, int stroke_size, SDL_Color color);
WidgetRect(int x, int y, int width, int height,
int radius = 0, int stroke_size = -1);
virtual void draw() override;
static Widget* builder(const nlohmann::json& j);
private:
// x, y - center of circle
// quadrant - 1--4
void draw_circle_corner(int x, int y, int quadrant);
};
#endif // WIDGET_RECT_H_

View File

@ -12,6 +12,7 @@
#include "sdl_helpers.h" #include "sdl_helpers.h"
#include "Widgets/Widget.h" #include "Widgets/Widget.h"
#include "Widgets/WidgetText.h" #include "Widgets/WidgetText.h"
#include "Widgets/WidgetRect.h"
using std::cout; using std::cout;
using std::endl; using std::endl;
@ -23,6 +24,7 @@ using nlohmann::json;
void init_builders(map<string, Widget*(*)(const json&)>& widget_builders) void init_builders(map<string, Widget*(*)(const json&)>& widget_builders)
{ {
widget_builders["text"] = &WidgetText::builder; widget_builders["text"] = &WidgetText::builder;
widget_builders["rect"] = &WidgetRect::builder;
} }
int main(int argc, char **argv) int main(int argc, char **argv)