210 lines
4.4 KiB
C++
210 lines
4.4 KiB
C++
#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()
|
|
{
|
|
if (nullptr == m_surface)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 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));
|
|
}
|
|
}
|
|
}
|
|
|
|
std::unique_ptr<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 std::make_unique<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);
|
|
}
|