diff --git a/include/swappy.h b/include/swappy.h index 7af4aa9..806da1b 100644 --- a/include/swappy.h +++ b/include/swappy.h @@ -46,18 +46,17 @@ struct swappy_paint_shape { }; struct swappy_paint_brush { - double x; - double y; double r; double g; double b; double a; double w; - enum swappy_brush_point_kind kind; + GSList *points; }; struct swappy_paint { enum swappy_paint_type type; + bool can_draw; union { struct swappy_paint_brush brush; struct swappy_paint_shape shape; @@ -119,10 +118,8 @@ struct swappy_state { struct swappy_box *geometry; - GSList *brushes; GSList *paints; - struct swappy_paint_shape *temp_shape; // Temporary shape - struct swappy_paint *temp_paint; // Temporary pain + struct swappy_paint *temp_paint; int argc; char **argv; diff --git a/src/application.c b/src/application.c index 2268540..77387e6 100644 --- a/src/application.c +++ b/src/application.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include "clipboard.h" @@ -12,21 +11,30 @@ #include "swappy.h" #include "wayland.h" -static void swappy_overlay_clear(struct swappy_state *state) { - if (state->brushes) { - g_slist_free_full(state->brushes, g_free); - state->brushes = NULL; +static void paint_free(gpointer data) { + struct swappy_paint *paint = (struct swappy_paint *)data; + + if (paint == NULL) { + return; } + switch (paint->type) { + case SWAPPY_PAINT_MODE_BRUSH: + g_slist_free_full(paint->content.brush.points, g_free); + break; + default: + g_free(paint); + } +} + +static void paint_free_all(struct swappy_state *state) { if (state->paints) { - g_slist_free_full(state->paints, g_free); + g_slist_free_full(state->paints, paint_free); state->paints = NULL; } - if (state->temp_paint) { - g_free(state->temp_paint); - state->temp_paint = NULL; - } + paint_free(state->temp_paint); + state->temp_paint = NULL; } static void switch_mode_to_brush(struct swappy_state *state) { @@ -76,9 +84,8 @@ void arrow_clicked_handler(GtkWidget *widget, struct swappy_state *state) { void application_finish(struct swappy_state *state) { g_debug("application is shutting down"); - swappy_overlay_clear(state); + paint_free_all(state); cairo_surface_destroy(state->cairo_surface); - g_free(state->temp_shape); g_free(state->storage_path); g_free(state->geometry_str); g_free(state->geometry); @@ -152,7 +159,7 @@ static void tools_menu_button_save_clicked_handler(GtkButton *button, static void tools_menu_button_clear_clicked_handler( GtkWidget *widget, struct swappy_state *state) { - swappy_overlay_clear(state); + paint_free_all(state); draw_state(state); } @@ -204,30 +211,34 @@ static void keypress_handler(GtkWidget *widget, GdkEventKey *event, } } -static void brush_add_point(struct swappy_state *state, double x, double y, - enum swappy_brush_point_kind kind) { - struct swappy_paint_brush *point = g_new(struct swappy_paint_brush, 1); - point->x = x; - point->y = y; - point->r = 1; - point->g = 0; - point->b = 0; - point->a = 1; - point->w = 2; - point->kind = kind; - - state->brushes = g_slist_append(state->brushes, point); -} - static void paint_add_temporary(struct swappy_state *state, double x, double y, enum swappy_paint_type type) { struct swappy_paint *paint = g_new(struct swappy_paint, 1); + struct swappy_point *brush; + paint->type = type; switch (type) { + case SWAPPY_PAINT_MODE_BRUSH: + paint->can_draw = true; + + paint->content.brush.r = 1; + paint->content.brush.g = 0; + paint->content.brush.b = 0; + paint->content.brush.a = 1; + paint->content.brush.w = 2; + + brush = g_new(struct swappy_point, 1); + brush->x = x; + brush->y = y; + + paint->content.brush.points = g_slist_append(NULL, brush); + break; case SWAPPY_PAINT_MODE_RECTANGLE: case SWAPPY_PAINT_MODE_ELLIPSE: case SWAPPY_PAINT_MODE_ARROW: + paint->can_draw = false; // need `to` vector + paint->content.shape.from.x = x; paint->content.shape.from.y = y; paint->content.shape.r = 1; @@ -251,47 +262,51 @@ static void paint_add_temporary(struct swappy_state *state, double x, double y, static void paint_update_temporary(struct swappy_state *state, double x, double y) { - if (!state->temp_paint) { + struct swappy_paint *paint = state->temp_paint; + struct swappy_point *brush; + GSList *points; + + if (!paint) { return; } - switch (state->temp_paint->type) { + switch (paint->type) { + case SWAPPY_PAINT_MODE_BRUSH: + points = paint->content.brush.points; + brush = g_new(struct swappy_point, 1); + brush->x = x; + brush->y = y; + + paint->content.brush.points = g_slist_append(points, brush); + break; case SWAPPY_PAINT_MODE_RECTANGLE: case SWAPPY_PAINT_MODE_ELLIPSE: case SWAPPY_PAINT_MODE_ARROW: - state->temp_paint->content.shape.to.x = x; - state->temp_paint->content.shape.to.y = y; + paint->content.shape.to.x = x; + paint->content.shape.to.y = y; + paint->can_draw = true; // all set break; default: - g_info("unable to update temporary paint: %d", state->temp_paint->type); + g_info("unable to update temporary paint: %d", paint->type); break; } } -static void paint_commit_temporary(struct swappy_state *state, double x, - double y) { - if (!state->temp_paint) { +static void paint_commit_temporary(struct swappy_state *state) { + struct swappy_paint *paint = state->temp_paint; + + if (!paint) { return; } - switch (state->temp_paint->type) { - case SWAPPY_PAINT_MODE_RECTANGLE: - case SWAPPY_PAINT_MODE_ELLIPSE: - case SWAPPY_PAINT_MODE_ARROW: - state->temp_paint->content.shape.to.x = x; - state->temp_paint->content.shape.to.y = y; - - struct swappy_paint *paint = - g_memdup(state->temp_paint, sizeof(struct swappy_paint)); - - state->paints = g_slist_append(state->paints, paint); - break; - default: - g_info("unable to commit temporary paint: %d", state->temp_paint->type); - break; + if (!paint->can_draw) { + paint_free(paint); + } else { + state->paints = g_slist_append(state->paints, paint); } - g_free(state->temp_paint); + // Set the temporary paint to NULL but keep the content in memory + // because it's now part of the GSList. state->temp_paint = NULL; } @@ -305,10 +320,12 @@ static void draw_area_button_press_handler(GtkWidget *widget, if (event->button == 1) { switch (state->mode) { + case SWAPPY_PAINT_MODE_BRUSH: case SWAPPY_PAINT_MODE_RECTANGLE: case SWAPPY_PAINT_MODE_ELLIPSE: case SWAPPY_PAINT_MODE_ARROW: paint_add_temporary(state, event->x, event->y, state->mode); + draw_state(state); break; default: return; @@ -326,13 +343,10 @@ static void draw_area_button_release_handler(GtkWidget *widget, switch (state->mode) { case SWAPPY_PAINT_MODE_BRUSH: - brush_add_point(state, event->x, event->y, SWAPPY_BRUSH_POINT_LAST); - draw_state(state); - break; case SWAPPY_PAINT_MODE_RECTANGLE: case SWAPPY_PAINT_MODE_ELLIPSE: case SWAPPY_PAINT_MODE_ARROW: - paint_commit_temporary(state, event->x, event->y); + paint_commit_temporary(state); draw_state(state); break; default: @@ -352,11 +366,6 @@ static void draw_area_motion_notify_handler(GtkWidget *widget, switch (state->mode) { case SWAPPY_PAINT_MODE_BRUSH: - if (is_button1_pressed) { - brush_add_point(state, event->x, event->y, SWAPPY_BRUSH_POINT_WITHIN); - draw_state(state); - } - break; case SWAPPY_PAINT_MODE_RECTANGLE: case SWAPPY_PAINT_MODE_ELLIPSE: case SWAPPY_PAINT_MODE_ARROW: diff --git a/src/draw.c b/src/draw.c index 18282b7..a1fe75a 100644 --- a/src/draw.c +++ b/src/draw.c @@ -185,30 +185,35 @@ static void draw_buffer(cairo_t *cr, struct swappy_state *state) { } } -static void draw_brushes(cairo_t *cr, struct swappy_state *state) { - for (GSList *brush = state->brushes; brush; brush = brush->next) { - GSList *brush_next = brush->next; - struct swappy_paint_brush *point = brush->data; +static void draw_brush(cairo_t *cr, struct swappy_paint_brush brush) { + cairo_set_source_rgba(cr, brush.r, brush.g, brush.b, brush.a); + cairo_set_line_width(cr, brush.w); + cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL); - if (brush_next && point->kind == SWAPPY_BRUSH_POINT_WITHIN) { - struct swappy_paint_brush *next = brush_next->data; - cairo_set_source_rgba(cr, point->r, point->g, point->b, point->a); - cairo_set_line_width(cr, point->w); - cairo_move_to(cr, point->x, point->y); - cairo_line_to(cr, next->x, next->y); - cairo_set_line_join(cr, CAIRO_LINE_JOIN_BEVEL); - cairo_stroke(cr); - } else { - cairo_set_source_rgba(cr, point->r, point->g, point->b, point->a); - cairo_set_line_width(cr, point->w); - cairo_rectangle(cr, point->x, point->y, 1, 1); - cairo_stroke(cr); + guint l = g_slist_length(brush.points); + + if (l == 1) { + struct swappy_point *point = g_slist_nth_data(brush.points, 0); + cairo_rectangle(cr, point->x, point->y, brush.w, brush.w); + cairo_fill(cr); + } else { + for (GSList *elem = brush.points; elem; elem = elem->next) { + struct swappy_point *point = elem->data; + cairo_line_to(cr, point->x, point->y); } + cairo_stroke(cr); } } static void draw_paint(cairo_t *cr, struct swappy_paint *paint) { + if (!paint->can_draw) { + return; + } + switch (paint->type) { + case SWAPPY_PAINT_MODE_BRUSH: + draw_brush(cr, paint->content.brush); + break; case SWAPPY_PAINT_MODE_RECTANGLE: case SWAPPY_PAINT_MODE_ELLIPSE: case SWAPPY_PAINT_MODE_ARROW: @@ -237,7 +242,6 @@ void draw_state(struct swappy_state *state) { cairo_set_source_rgb(cr, 1, 1, 1); draw_buffer(cr, state); - draw_brushes(cr, state); draw_paints(cr, state); // Drawing is finished, notify the GtkDrawingArea it needs to be redrawn.