feat: add circle tool

This commit is contained in:
Beriff
2026-03-11 09:46:30 +07:00
parent 00031d145e
commit 6c8ca19fbf
7 changed files with 67 additions and 36 deletions

View File

@@ -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",

View File

@@ -10,7 +10,8 @@ typedef enum VektorAppTool {
VektorSelectionTool,
VektorLineTool,
VektorPolygonTool,
VektorRectangleTool
VektorRectangleTool,
VektorCircleTool
} VektorAppTool;
typedef struct VektorAppState {

View File

@@ -1,4 +1,5 @@
#include "primitives.h"
#include "src/core/vector.h"
#include <assert.h>
#include <math.h>
#include <stddef.h>
@@ -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;

View File

@@ -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);

View File

@@ -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}; }

View File

@@ -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);

View File

@@ -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);
}