Skip to content

Commit

Permalink
feat(paint): introduce text paint
Browse files Browse the repository at this point in the history
  • Loading branch information
jtheoof committed Jan 4, 2020
1 parent 87fd4db commit 3347bf2
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ Install dependencies:
- meson
- wayland
- cairo
- pango
- gtk

Optional dependencies:
Expand Down
9 changes: 8 additions & 1 deletion include/paint.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
#pragma once

#include <gdk/gdk.h>

#include "swappy.h"

void paint_add_temporary(struct swappy_state *state, double x, double y,
enum swappy_paint_type type);
void paint_update_temporary(struct swappy_state *state, double x, double y);
void paint_update_temporary_shape(struct swappy_state *state, double x,
double y);
void paint_update_temporary_text(struct swappy_state *state,
GdkEventKey *event);
void paint_update_temporary_text_clip(struct swappy_state *state, gdouble x,
gdouble y);
void paint_commit_temporary(struct swappy_state *state);

void paint_free(gpointer data);
Expand Down
22 changes: 22 additions & 0 deletions include/swappy.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

#define SWAPPY_STROKE_SIZE_MIN 1
#define SWAPPY_STROKE_SIZE_DEFAULT 5
#define SWAPPY_TEXT_FONT_DEFAULT "serif"
#define SWAPPY_TEXT_SIZE_DEFAULT 21
#define SWAPPY_STROKE_SIZE_MAX 50

enum swappy_paint_type {
Expand All @@ -28,11 +30,29 @@ enum swappy_paint_type {
SWAPPY_PAINT_MODE_ARROW, /* Arrow shapes */
};

enum swappy_text_mode {
SWAPPY_TEXT_MODE_EDIT = 0,
SWAPPY_TEXT_MODE_DONE,
};

struct swappy_point {
gdouble x;
gdouble y;
};

struct swappy_paint_text {
double r;
double g;
double b;
double a;
double s;
gchar *text;
int cursor;
struct swappy_point from;
struct swappy_point to;
enum swappy_text_mode mode;
};

struct swappy_paint_shape {
double r;
double g;
Expand All @@ -59,6 +79,7 @@ struct swappy_paint {
union {
struct swappy_paint_brush brush;
struct swappy_paint_shape shape;
struct swappy_paint_text text;
} content;
};

Expand All @@ -75,6 +96,7 @@ struct swappy_state_settings {
double b;
double a;
double w;
double t;
};

struct swappy_state_ui {
Expand Down
7 changes: 7 additions & 0 deletions include/util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

#pragma once

#include <glib.h>

void string_remove_at(char *str, int pos);
gchar *string_insert_char_at(gchar *str, gchar c, int pos);
3 changes: 3 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ if cc.get_id() == 'clang'
endif

cairo = dependency('cairo')
pango = dependency('pango')
math = cc.find_library('m')
realtime = cc.find_library('rt')
gtk = dependency('gtk+-3.0', version: '>=3.20.0')
Expand Down Expand Up @@ -58,10 +59,12 @@ executable(
'src/paint.c',
'src/render.c',
'src/notification.c',
'src/util.c',
'src/wayland.c',
]),
dependencies: [
cairo,
pango,
client_protos,
gtk,
libnotify,
Expand Down
24 changes: 23 additions & 1 deletion src/application.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ void copy_clicked_handler(GtkWidget *widget, struct swappy_state *state) {

void window_keypress_handler(GtkWidget *widget, GdkEventKey *event,
struct swappy_state *state) {
if (state->temp_paint && state->mode == SWAPPY_PAINT_MODE_TEXT) {
paint_update_temporary_text(state, event);
render_state(state);
return;
}
if (event->state & GDK_CONTROL_MASK) {
switch (event->keyval) {
case GDK_KEY_c:
Expand Down Expand Up @@ -336,8 +341,10 @@ void draw_area_button_press_handler(GtkWidget *widget, GdkEventButton *event,
case SWAPPY_PAINT_MODE_RECTANGLE:
case SWAPPY_PAINT_MODE_ELLIPSE:
case SWAPPY_PAINT_MODE_ARROW:
case SWAPPY_PAINT_MODE_TEXT:
paint_add_temporary(state, event->x, event->y, state->mode);
render_state(state);
update_ui_undo_redo(state);
break;
default:
return;
Expand All @@ -346,6 +353,8 @@ void draw_area_button_press_handler(GtkWidget *widget, GdkEventButton *event,
}
void draw_area_motion_notify_handler(GtkWidget *widget, GdkEventMotion *event,
struct swappy_state *state) {
gdouble x = event->x;
gdouble y = event->y;
GdkDisplay *display = gdk_display_get_default();
GdkWindow *window = event->window;
GdkCursor *crosshair = gdk_cursor_new_for_display(display, GDK_CROSSHAIR);
Expand All @@ -359,7 +368,13 @@ void draw_area_motion_notify_handler(GtkWidget *widget, GdkEventMotion *event,
case SWAPPY_PAINT_MODE_ELLIPSE:
case SWAPPY_PAINT_MODE_ARROW:
if (is_button1_pressed) {
paint_update_temporary(state, event->x, event->y);
paint_update_temporary_shape(state, x, y);
render_state(state);
}
break;
case SWAPPY_PAINT_MODE_TEXT:
if (is_button1_pressed) {
paint_update_temporary_text_clip(state, x, y);
render_state(state);
}
break;
Expand All @@ -384,6 +399,12 @@ void draw_area_button_release_handler(GtkWidget *widget, GdkEventButton *event,
render_state(state);
update_ui_undo_redo(state);
break;
case SWAPPY_PAINT_MODE_TEXT:
if (state->temp_paint && !state->temp_paint->can_draw) {
paint_free(state->temp_paint);
state->temp_paint = NULL;
}
break;
default:
return;
}
Expand Down Expand Up @@ -620,6 +641,7 @@ bool application_init(struct swappy_state *state) {
state->settings.b = 0;
state->settings.a = 1;
state->settings.w = SWAPPY_STROKE_SIZE_DEFAULT;
state->settings.t = SWAPPY_TEXT_SIZE_DEFAULT;

return true;
}
Expand Down
131 changes: 123 additions & 8 deletions src/paint.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "paint.h"

#include "util.h"

void paint_free(gpointer data) {
struct swappy_paint *paint = (struct swappy_paint *)data;

Expand All @@ -10,11 +12,14 @@ void paint_free(gpointer data) {
switch (paint->type) {
case SWAPPY_PAINT_MODE_BRUSH:
g_list_free_full(paint->content.brush.points, g_free);
g_free(paint);
break;
case SWAPPY_PAINT_MODE_TEXT:
g_free(paint->content.text.text);
break;
default:
g_free(paint);
break;
}
g_free(paint);
}

void paint_free_list(GList **list) {
Expand All @@ -41,9 +46,19 @@ void paint_add_temporary(struct swappy_state *state, double x, double y,
double b = state->settings.b;
double a = state->settings.a;
double w = state->settings.w;
double t = state->settings.t;

paint->type = type;

if (state->temp_paint) {
if (type == SWAPPY_PAINT_MODE_TEXT) {
paint_commit_temporary(state);
} else {
g_free(state->temp_paint);
state->temp_paint = NULL;
}
}

switch (type) {
case SWAPPY_PAINT_MODE_BRUSH:
paint->can_draw = true;
Expand Down Expand Up @@ -74,19 +89,32 @@ void paint_add_temporary(struct swappy_state *state, double x, double y,
paint->content.shape.w = w;
paint->content.shape.type = type;
break;
case SWAPPY_PAINT_MODE_TEXT:
paint->can_draw = false;

paint->content.text.from.x = x;
paint->content.text.from.y = y;
paint->content.text.r = r;
paint->content.text.g = g;
paint->content.text.b = b;
paint->content.text.a = a;
paint->content.text.s = t;
paint->content.text.cursor = 0;
paint->content.text.mode = SWAPPY_TEXT_MODE_EDIT;
paint->content.text.text = g_new(gchar, 1);
paint->content.text.text[0] = '\0';
break;

default:
g_info("unable to add temporary paint: %d", type);
break;
}

if (state->temp_paint) {
g_free(state->temp_paint);
}

state->temp_paint = paint;
}

void paint_update_temporary(struct swappy_state *state, double x, double y) {
void paint_update_temporary_shape(struct swappy_state *state, double x,
double y) {
struct swappy_paint *paint = state->temp_paint;
struct swappy_point *brush;
GList *points;
Expand All @@ -113,18 +141,105 @@ void paint_update_temporary(struct swappy_state *state, double x, double y) {
paint->content.shape.to.y = y;
break;
default:
g_info("unable to update temporary paint: %d", paint->type);
g_info("unable to update temporary paint when type is: %d", paint->type);
break;
}
}

void paint_update_temporary_text(struct swappy_state *state,
GdkEventKey *event) {
struct swappy_paint *paint = state->temp_paint;
struct swappy_paint_text *text;
char buffer[32];
guint32 unicode;

if (!paint || paint->type != SWAPPY_PAINT_MODE_TEXT) {
g_warning("trying to update text but not in text mode");
return;
}

text = &paint->content.text;

switch (event->keyval) {
case GDK_KEY_Escape:
paint_commit_temporary(state);
break;
case GDK_KEY_BackSpace:
if (strlen(text->text) > 0) {
string_remove_at(text->text, text->cursor - 1);
text->cursor--;
}
break;
case GDK_KEY_Delete:
if (strlen(text->text) > 0) {
string_remove_at(text->text, text->cursor);
}
break;
case GDK_KEY_Left:
text->cursor--;
break;
case GDK_KEY_Right:
text->cursor++;
break;
default:
unicode = gdk_keyval_to_unicode(event->keyval);
if (unicode != 0) {
int ll = g_unichar_to_utf8(unicode, buffer);
buffer[ll] = '\0';
g_debug("received unicode: %d - utf8: %s (%d)", unicode, buffer, ll);
g_debug("text before: %s - cursor: %d", text->text, text->cursor);
char *new_text =
string_insert_char_at(text->text, buffer[0], text->cursor);
g_free(text->text);
text->text = new_text;
text->cursor++;
}
break;
}

if (text->cursor < 0) {
text->cursor = 0;
} else if (text->cursor > (int)strlen(text->text)) {
text->cursor = (int)strlen(text->text);
}

g_debug("text is now: %s", text->text);
}

void paint_update_temporary_text_clip(struct swappy_state *state, gdouble x,
gdouble y) {
struct swappy_paint *paint = state->temp_paint;

if (!paint) {
return;
}

g_assert(paint->type == SWAPPY_PAINT_MODE_TEXT);

paint->can_draw = true;
paint->content.text.to.x = x;
paint->content.text.to.y = y;
}

void paint_commit_temporary(struct swappy_state *state) {
struct swappy_paint *paint = state->temp_paint;

if (!paint) {
return;
}

switch (paint->type) {
case SWAPPY_PAINT_MODE_TEXT:
if (strlen(paint->content.text.text) == 0) {
paint->can_draw = false;
}
paint->content.text.mode = SWAPPY_TEXT_MODE_DONE;
break;
default:
g_info("unable to update temporary text when type is: %d", paint->type);
break;
}

if (!paint->can_draw) {
paint_free(paint);
} else {
Expand Down
Loading

0 comments on commit 3347bf2

Please sign in to comment.