From 6c8ca19fbfa6a009453bd0efbaa9f304c83782ae Mon Sep 17 00:00:00 2001 From: Beriff Date: Wed, 11 Mar 2026 09:46:30 +0700 Subject: [PATCH] feat: add circle tool --- src/application/applicationstate.c | 39 ++++++++++++++++++++++-------- src/application/applicationstate.h | 3 ++- src/core/primitives.c | 34 ++++++++++++++++++++++---- src/core/primitives.h | 1 + src/core/vector.h | 2 ++ src/main.c | 10 -------- src/ui/uicontroller.c | 14 +++-------- 7 files changed, 67 insertions(+), 36 deletions(-) diff --git a/src/application/applicationstate.c b/src/application/applicationstate.c index c5263e0..00fa350 100644 --- a/src/application/applicationstate.c +++ b/src/application/applicationstate.c @@ -157,6 +157,26 @@ begin_click_dispatch: } vektor_polygon_add_point(state->selectedShape->primitive.polygon, pos); + vektor_shapes_update_bbox(state->shapeBuffer); + } else if (state->selectedTool == VektorCircleTool) { + + VektorCircle* circle = vektor_circle_new(); + VektorPrimitive circlePrimitive = + (VektorPrimitive){.kind = VEKTOR_CIRCLE, .circle = *circle}; + VektorStyle style = (VektorStyle){ + .stroke_color = state->currentColor, .stroke_width = 0.01}; + vektor_shapebuffer_add_shape( + state->shapeBuffer, + vektor_shape_new(circlePrimitive, style, 0)); + + state->selectedShape = + &(state->shapeBuffer->shapes[state->shapeBuffer->count - 1]); + + vektor_circle_free(circle); + + vektor_circle_set_center(&state->selectedShape->primitive.circle, pos); + vektor_circle_set_radius(&state->selectedShape->primitive.circle, 0.1f); + vektor_shapes_update_bbox(state->shapeBuffer); } else if (state->selectedTool == VektorRectangleTool) { @@ -185,7 +205,6 @@ begin_click_dispatch: state->shapeBuffer->shapes[i].primitive); if (vektor_bbox_isinside(bbox, pos)) { state->selectedShape = &(state->shapeBuffer->shapes[i]); - g_print("%d", state->selectedShape == NULL); return; } } @@ -217,22 +236,21 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) { data_selecttool->state = stateOut; data_selecttool->tool = VektorSelectionTool; + button_tool_set_data* data_circletool = + malloc(sizeof(button_tool_set_data)); + data_circletool->state = stateOut; + data_circletool->tool = VektorCircleTool; + data_circletool->revealer = wstate->workspaceRevealerShapes; + // populate appstate stateOut->startupTime = g_get_monotonic_time(); - stateOut->shapeBuffer = malloc(sizeof(VektorShapeBuffer)); *stateOut->shapeBuffer = (VektorShapeBuffer){0}; - - VektorCircle circ = (VektorCircle){.center = (V2){0, 0}, .radius = 0.3}; - VektorShape shp = vektor_shape_new( - (VektorPrimitive){.kind = VEKTOR_CIRCLE, .circle = circ}, - (VektorStyle){.stroke_color = stateOut->currentColor, 0.01}, 0); - vektor_shapebuffer_add_shape(stateOut->shapeBuffer, shp); - stateOut->canvas = malloc(sizeof(VektorCanvas)); stateOut->widgetState = wstate; stateOut->currentColor = vektor_color_solid(0, 0, 0); stateOut->selectedShape = NULL; + VektorCanvasRenderInfo* renderInfo = malloc(sizeof(VektorCanvasRenderInfo)); renderInfo->zoom = 1; renderInfo->panX = 0; @@ -245,13 +263,14 @@ void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) { renderInfo->canvasMat = m33_identity(); vektor_canvas_init(wstate, stateOut->canvas, renderInfo); stateOut->renderInfo = renderInfo; + // link all the buttons g_signal_connect(G_OBJECT(wstate->workspaceButtonLineTool), "clicked", G_CALLBACK(appstate_set_tool), data_linetool); g_signal_connect(G_OBJECT(wstate->workspaceButtonRectTool), "clicked", G_CALLBACK(appstate_set_tool), data_rectangletool); g_signal_connect(G_OBJECT(wstate->workspaceButtonCircleTool), "clicked", - G_CALLBACK(appstate_set_tool), data_linetool); + G_CALLBACK(appstate_set_tool), data_circletool); g_signal_connect(G_OBJECT(wstate->workspaceButtonPolygonTool), "clicked", G_CALLBACK(appstate_set_tool), data_polygontool); g_signal_connect(G_OBJECT(wstate->workspaceButtonSelectionTool), "clicked", diff --git a/src/application/applicationstate.h b/src/application/applicationstate.h index 21a8520..2e48c2a 100644 --- a/src/application/applicationstate.h +++ b/src/application/applicationstate.h @@ -10,7 +10,8 @@ typedef enum VektorAppTool { VektorSelectionTool, VektorLineTool, VektorPolygonTool, - VektorRectangleTool + VektorRectangleTool, + VektorCircleTool } VektorAppTool; typedef struct VektorAppState { diff --git a/src/core/primitives.c b/src/core/primitives.c index 568e904..7cacf75 100644 --- a/src/core/primitives.c +++ b/src/core/primitives.c @@ -1,4 +1,5 @@ #include "primitives.h" +#include "src/core/vector.h" #include #include #include @@ -74,6 +75,10 @@ void vektor_circle_set_radius(VektorCircle* circle, double radius) { circle->radius = radius; } +void vektor_circle_free(VektorCircle* circle) { + free(circle); +} + VektorRectangle* vektor_rectangle_new(void) { VektorRectangle* rct = malloc(sizeof(VektorRectangle)); rct->start = (V2){.x = 0, .y = 0}; @@ -107,15 +112,23 @@ void vektor_shapebuffer_add_shape(VektorShapeBuffer* buffer, } VektorBBox vektor_polyline_get_bbox(VektorPrimitive prim) { - float min_x, max_x, min_y, max_y; - for (size_t i = 0; i < prim.polyline->count; i++) { - V2 p = prim.polyline->points[i]; + V2 first = prim.polyline->points[0]; + + float min_x = first.x; + float max_x = first.x; + float min_y = first.y; + float max_y = first.y; + + for (size_t i = 1; i < prim.polygon->count; i++) { + V2 p = prim.polygon->points[i]; + min_x = fminf(min_x, p.x); min_y = fminf(min_y, p.y); - max_x = fminf(max_x, p.x); - max_y = fminf(max_y, p.y); + max_x = fmaxf(max_x, p.x); + max_y = fmaxf(max_y, p.y); } + return (VektorBBox){(V2){min_x, min_y}, (V2){max_x, max_y}}; } @@ -144,6 +157,13 @@ VektorBBox vektor_rectangle_get_bbox(VektorPrimitive prim) { return (VektorBBox){prim.rectangle.start, prim.rectangle.end}; } +VektorBBox vektor_circle_get_bbox(VektorPrimitive prim) { + return (VektorBBox){ + vec2_sub(prim.circle.center, vec2_fromfloat(prim.circle.radius)), + vec2_add(prim.circle.center, vec2_fromfloat(prim.circle.radius)) + }; +} + VektorBBox vektor_primitive_get_bbox(VektorPrimitive prim) { switch (prim.kind) { case VEKTOR_POLYLINE: @@ -158,6 +178,10 @@ VektorBBox vektor_primitive_get_bbox(VektorPrimitive prim) { return vektor_rectangle_get_bbox(prim); break; + case VEKTOR_CIRCLE: + return vektor_circle_get_bbox(prim); + break; + default: // TODO: fill in all primitives break; diff --git a/src/core/primitives.h b/src/core/primitives.h index 8c93193..c736f8e 100644 --- a/src/core/primitives.h +++ b/src/core/primitives.h @@ -56,6 +56,7 @@ void vektor_polygon_free(VektorPolygon* pl); VektorCircle* vektor_circle_new(void); void vektor_circle_set_center(VektorCircle* circle, V2 point); void vektor_circle_set_radius(VektorCircle* circle, double radius); +void vektor_circle_free(VektorCircle* circle); VektorRectangle* vektor_rectangle_new(void); void vektor_rectangle_set_end(VektorRectangle* rct, V2 point); diff --git a/src/core/vector.h b/src/core/vector.h index 2cfea10..dd53e9e 100644 --- a/src/core/vector.h +++ b/src/core/vector.h @@ -14,6 +14,8 @@ typedef struct { double z; } V3; +static inline V2 vec2_fromfloat(const float f) { return (V2){f,f}; } + static inline V3 vec2_vector(const V2 v) { return (V3){v.x, v.y, 0}; } static inline V3 vec2_point(const V2 v) { return (V3){v.x, v.y, 1}; } diff --git a/src/main.c b/src/main.c index 7488bcc..9220d99 100644 --- a/src/main.c +++ b/src/main.c @@ -1,19 +1,12 @@ #include "glib.h" #include "gtk/gtk.h" #include "src/application/applicationstate.h" -#include "src/core/primitives.h" #include "stdio.h" #include "stdlib.h" #include "./application/applicationstate.h" -#include "./core/raster.h" #include "./ui/uicontroller.h" -#include "./ui/vektorcanvas.h" -#include "./util/color.h" -static void on_map(GtkWidget* window, gpointer user_data) { - vektor_uictrl_map((VektorWidgetState*)user_data); -} static int update_callback(gpointer data) { VektorAppState* appstate = (VektorAppState*)data; @@ -30,9 +23,6 @@ static void activate(GtkApplication* app, gpointer user_data) { VektorAppState* app_state = (VektorAppState*)malloc(sizeof(VektorAppState)); vektor_appstate_new(widget_state, app_state); - g_signal_connect(widget_state->window, "map", G_CALLBACK(on_map), - widget_state); - g_timeout_add(1, update_callback, app_state); gtk_window_present(widget_state->window); diff --git a/src/ui/uicontroller.c b/src/ui/uicontroller.c index 5b12982..8d6f2bd 100644 --- a/src/ui/uicontroller.c +++ b/src/ui/uicontroller.c @@ -31,11 +31,6 @@ void vektor_uictrl_init(GtkApplication* app, VektorWidgetState* stateOut) { GtkIconTheme* theme = gtk_icon_theme_get_for_display(gdk_display_get_default()); - /*if (gtk_icon_theme_has_icon(theme, "vektor-circle-symbolic")) - g_print("GTK sees it!\n"); - else - g_print("Still invisible...\n");*/ - // populate state stateOut->window = GTK_WINDOW(gtk_builder_get_object(builder, "main_window")); @@ -75,10 +70,9 @@ void vektor_uictrl_init(GtkApplication* app, VektorWidgetState* stateOut) { gtk_window_set_title(stateOut->window, "Vektor"); gtk_window_set_default_size(stateOut->window, 800, 600); + // Set dimensions + gtk_paned_set_position(stateOut->workspacePaned, 800 * .7); + gtk_paned_set_position(stateOut->sidepanelPaned, 250); + g_object_unref(builder); } - -void vektor_uictrl_map(VektorWidgetState* state) { - gtk_paned_set_position(state->workspacePaned, 800 * .7); - gtk_paned_set_position(state->sidepanelPaned, 250); -}