diff --git a/Makefile b/Makefile index f7117bc..d5a6d5d 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ src_files += sdl_helpers.cpp src_files += Widgets/Widget.cpp src_files += Widgets/WidgetText.cpp +src_files += Widgets/WidgetRect.cpp all: g++ $(src_files) -Wall -lSDL2 -lSDL2_ttf -lSDL2_image -o trmnl_sdl diff --git a/Widgets/WidgetRect.cpp b/Widgets/WidgetRect.cpp new file mode 100644 index 0000000..2051450 --- /dev/null +++ b/Widgets/WidgetRect.cpp @@ -0,0 +1,204 @@ +#include "WidgetRect.h" + +#include + +#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 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); +} diff --git a/Widgets/WidgetRect.h b/Widgets/WidgetRect.h new file mode 100644 index 0000000..f5ab905 --- /dev/null +++ b/Widgets/WidgetRect.h @@ -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_ diff --git a/main.cpp b/main.cpp index ad3f6fd..03f4698 100644 --- a/main.cpp +++ b/main.cpp @@ -12,6 +12,7 @@ #include "sdl_helpers.h" #include "Widgets/Widget.h" #include "Widgets/WidgetText.h" +#include "Widgets/WidgetRect.h" using std::cout; using std::endl; @@ -23,6 +24,7 @@ using nlohmann::json; void init_builders(map& widget_builders) { widget_builders["text"] = &WidgetText::builder; + widget_builders["rect"] = &WidgetRect::builder; } int main(int argc, char **argv)