diff --git a/meson.build b/meson.build index c2165cd..5e4838c 100644 --- a/meson.build +++ b/meson.build @@ -18,7 +18,8 @@ src = files( 'src/core/primitives.c', 'src/core/raster.c', 'src/ui/uicontroller.c', - 'src/ui/vektorcanvas.c' + 'src/ui/vektorcanvas.c', + 'src/application/applicationstate.c' ) executable( diff --git a/src/application/applicationstate.c b/src/application/applicationstate.c index e69de29..115d915 100644 --- a/src/application/applicationstate.c +++ b/src/application/applicationstate.c @@ -0,0 +1,85 @@ +#include "./applicationstate.h" +#include "src/core/primitives.h" +#include "src/core/raster.h" +#include "src/ui/vektorcanvas.h" + +typedef struct button_tool_set_data { + VektorAppState* state; + VektorAppTool tool; +} button_tool_set_data; + +static void appstate_set_tool(GtkButton* button, gpointer user_data) { + button_tool_set_data* data = (button_tool_set_data*)user_data; + data->state->selectedTool = data->tool; + + // setting tool also resets selected primitive + data->state->selectedPrimitive = NULL; +} + +static void canvas_onclick(GtkGestureClick* gesture, int n_press, double x, double y, gpointer user_data) { + vektor_appstate_canvas_click(user_data, x, y); +} + +void vektor_appstate_canvas_click(VektorAppState* state, double x, double y) { + V2 pos = (V2){x,y}; + + begin_click_dispatch: + if(state->selectedTool == VektorLineTool) { + // create new polyline primitive if none is selected + if(state->selectedPrimitive == NULL) { + + VektorPolyline* line = vektor_polyline_new(); + VektorPrimitive linePrimitive = (VektorPrimitive){ + .kind = VEKTOR_POLYLINE, .polyline = line + }; + vektor_primitivebuffer_add_primitive(state->primitiveBuffer, linePrimitive); + + state->selectedPrimitive = + &(state->primitiveBuffer->primitives[state->primitiveBuffer->count - 1]); + + } else if (state->selectedPrimitive->kind != VEKTOR_POLYLINE) { + // selecting a tool resets the selection, so this condition + // should not happen + g_warning("Invalid selected primitive; polyline expected"); + state->selectedPrimitive = NULL; + goto begin_click_dispatch; // retry + } + + + vektor_polyline_add_point(state->selectedPrimitive->polyline, pos); + } + + vektor_framebuffer_rasterize(state->frameBuffer, state->primitiveBuffer); + vektor_canvas_drawfrom(state->frameBuffer, state->canvas); + vektor_canvas_update(state->canvas); +} + +void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut) { + button_tool_set_data* data_linetool = malloc(sizeof(button_tool_set_data)); + data_linetool->state = stateOut; + data_linetool->tool = VektorLineTool; + + // populate appstate + stateOut->primitiveBuffer = malloc(sizeof(VektorPrimitiveBuffer)); + *stateOut->primitiveBuffer = (VektorPrimitiveBuffer){0}; + stateOut->frameBuffer = malloc(sizeof(VektorFramebuffer)); + *stateOut->frameBuffer = vektor_framebuffer_new(400, 400); + stateOut->canvas = malloc(sizeof(VektorCanvas)); + vektor_canvas_init(wstate, stateOut->canvas); + + // link all the buttons + g_signal_connect( + G_OBJECT(wstate->workspaceButtonLinetool), + "clicked", G_CALLBACK(appstate_set_tool), data_linetool); + + // Add click gesture to canvas + GtkGesture* canvasClickGesture = gtk_gesture_click_new(); + g_signal_connect( + G_OBJECT(canvasClickGesture), + "pressed", G_CALLBACK(canvas_onclick), stateOut + ); + gtk_widget_add_controller( + GTK_WIDGET(wstate->workspaceCanvas), + GTK_EVENT_CONTROLLER(canvasClickGesture) + ); +} \ No newline at end of file diff --git a/src/application/applicationstate.h b/src/application/applicationstate.h index dc88a1a..1c143d6 100644 --- a/src/application/applicationstate.h +++ b/src/application/applicationstate.h @@ -1,7 +1,29 @@ +#ifndef VKTR_APPSTATE_H +#define VKTR_APPSTATE_H + +#include "../ui/uicontroller.h" +#include "../core/primitives.h" +#include "src/core/raster.h" +#include "../ui/vektorcanvas.h" + typedef enum VektorAppTool { - CircleTool + VektorLineTool } VektorAppTool; typedef struct VektorAppState { VektorAppTool selectedTool; -} VektorAppState; \ No newline at end of file + VektorPrimitive* selectedPrimitive; + + // Logic space + VektorPrimitiveBuffer* primitiveBuffer; + // Pixel space + VektorFramebuffer* frameBuffer; + // View space + VektorCanvas* canvas; + +} VektorAppState; + +void vektor_appstate_new(VektorWidgetState* wstate, VektorAppState* stateOut); +void vektor_appstate_canvas_click(VektorAppState* state, double x, double y); + +#endif \ No newline at end of file diff --git a/src/core/raster.c b/src/core/raster.c index ff4b0cb..83f255b 100644 --- a/src/core/raster.c +++ b/src/core/raster.c @@ -84,7 +84,7 @@ void vektor_framebuffer_drawline(VektorFramebuffer *fb, V2 a, V2 b, } } -void rasterize(VektorFramebuffer *fb, VektorPrimitiveBuffer *prims) { +void vektor_framebuffer_rasterize(VektorFramebuffer *fb, VektorPrimitiveBuffer *prims) { EdgeBuffer edges = {0}; for (size_t i = 0; i < prims->count; i++) { VektorPrimitive *p = &prims->primitives[i]; diff --git a/src/core/raster.h b/src/core/raster.h index 92aceaa..b35bd6c 100644 --- a/src/core/raster.h +++ b/src/core/raster.h @@ -40,6 +40,6 @@ void vektor_framebuffer_putpixel(VektorFramebuffer *fb, int x, int y, void vektor_framebuffer_drawline(VektorFramebuffer *fb, V2 a, V2 b, VektorColor color); -void rasterize(VektorFramebuffer *fb, VektorPrimitiveBuffer *primitives); +void vektor_framebuffer_rasterize(VektorFramebuffer *fb, VektorPrimitiveBuffer *primitives); #endif // RASTER_H_ diff --git a/src/main.c b/src/main.c index a53ce02..ba4318d 100644 --- a/src/main.c +++ b/src/main.c @@ -1,4 +1,5 @@ #include "gtk/gtk.h" +#include "src/application/applicationstate.h" #include "src/core/primitives.h" #include "stdio.h" #include "stdlib.h" @@ -7,58 +8,21 @@ #include "./ui/uicontroller.h" #include "./ui/vektorcanvas.h" #include "./util/color.h" +#include "./application/applicationstate.h" static void on_map(GtkWidget *window, gpointer user_data) { vektor_uictrl_map((VektorWidgetState *)user_data); } -void write_ppm(const char *path, const VektorFramebuffer *fb) { - FILE *f = fopen(path, "wb"); - if (!f) - abort(); - - fprintf(f, "P6\n%d %d\n255\n", fb->width, fb->height); - fwrite(fb->pixels, 1, fb->width * fb->height * 4, f); - fclose(f); -} - static void activate(GtkApplication *app, gpointer user_data) { - VektorFramebuffer fb = vektor_framebuffer_new(400, 400); - - VektorPolygon triangle = *vektor_polygon_new(); - vektor_polygon_add_point(&triangle, (V2){50, 150}); - vektor_polygon_add_point(&triangle, (V2){200, 180}); - vektor_polygon_add_point(&triangle, (V2){120, 300}); - - VektorPolygon star = *vektor_polygon_new(); - vektor_polygon_add_point(&star, (V2){150, 40}); - vektor_polygon_add_point(&star, (V2){180, 110}); - vektor_polygon_add_point(&star, (V2){260, 110}); - vektor_polygon_add_point(&star, (V2){200, 160}); - vektor_polygon_add_point(&star, (V2){220, 240}); - vektor_polygon_add_point(&star, (V2){150, 190}); - vektor_polygon_add_point(&star, (V2){80, 240}); - vektor_polygon_add_point(&star, (V2){100, 160}); - vektor_polygon_add_point(&star, (V2){40, 110}); - vektor_polygon_add_point(&star, (V2){120, 110}); - - VektorPrimitiveBuffer prims = {0}; - vektor_primitivebuffer_add_primitive( - &prims, (VektorPrimitive){.kind = VEKTOR_POLYGON, .polygon = &triangle}); - vektor_primitivebuffer_add_primitive( - &prims, (VektorPrimitive){.kind = VEKTOR_POLYGON, .polygon = &star}); - - rasterize(&fb, &prims); VektorWidgetState *widget_state = (VektorWidgetState *)malloc(sizeof(VektorWidgetState)); vektor_uictrl_init(app, widget_state); + VektorAppState* app_state = + (VektorAppState *)malloc(sizeof(VektorAppState)); + vektor_appstate_new(widget_state, app_state); - VektorCanvas *canvas = (VektorCanvas *)malloc(sizeof(VektorCanvas)); - vektor_canvas_init(widget_state, canvas); - vektor_canvas_fill(canvas, vektor_color_new(255, 0, 0, 255)); - vektor_canvas_drawfrom(&fb, canvas); - vektor_canvas_update(canvas); g_signal_connect(widget_state->window, "map", G_CALLBACK(on_map), widget_state); diff --git a/src/ui/uicontroller.c b/src/ui/uicontroller.c index 3300251..0a7ab85 100644 --- a/src/ui/uicontroller.c +++ b/src/ui/uicontroller.c @@ -1,5 +1,6 @@ #include "uicontroller.h" #include "gdk/gdk.h" +#include "glib-object.h" #include "gtk/gtk.h" #include "gtk/gtkcssprovider.h" @@ -12,6 +13,7 @@ void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut) { g_error("Fatal: %s", error->message); } + // Load css GtkCssProvider* provider = gtk_css_provider_new(); gtk_css_provider_load_from_path(provider, "./ui/main.css"); gtk_style_context_add_provider_for_display(gdk_display_get_default(), @@ -19,12 +21,16 @@ void vektor_uictrl_init(GtkApplication *app, VektorWidgetState *stateOut) { GTK_STYLE_PROVIDER_PRIORITY_APPLICATION ); + // populate state stateOut->window = GTK_WINDOW(gtk_builder_get_object(builder, "main_window")); stateOut->workspacePaned = GTK_PANED(gtk_builder_get_object(builder, "workspace_paned")); stateOut->workspaceCanvas = GTK_PICTURE(gtk_builder_get_object(builder, "workspace")); + stateOut->workspaceButtonLinetool = + GTK_BUTTON(gtk_builder_get_object(builder, "button_linetool")); + // Set window properties gtk_window_set_application(stateOut->window, app); gtk_window_set_title(stateOut->window, "Vektor"); gtk_window_set_default_size(stateOut->window, 800, 600); diff --git a/src/ui/uicontroller.h b/src/ui/uicontroller.h index e6e5d9b..d2ee11d 100644 --- a/src/ui/uicontroller.h +++ b/src/ui/uicontroller.h @@ -12,6 +12,8 @@ typedef struct VektorWidgetState { GtkPaned *workspacePaned; GtkPicture *workspaceCanvas; + GtkButton* workspaceButtonLinetool; + // GtkWidget* Workspace } VektorWidgetState; diff --git a/ui/main.ui b/ui/main.ui index 60827bd..fa33915 100644 --- a/ui/main.ui +++ b/ui/main.ui @@ -67,7 +67,7 @@ - + insert-object-symbolic