Skip to content

Commit

Permalink
fix(text): properly handle utf-8 chars
Browse files Browse the repository at this point in the history
UTF-8 characters are now handled porperly. Also re-worked some helper
functions with UTF-8 in mind.

Closes #43
  • Loading branch information
jtheoof committed Jul 6, 2020
1 parent 59d60db commit d8550b2
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 31 deletions.
2 changes: 1 addition & 1 deletion include/swappy.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ struct swappy_paint_text {
double s;
gchar *font;
gchar *text;
size_t cursor;
glong cursor;
struct swappy_point from;
struct swappy_point to;
enum swappy_text_mode mode;
Expand Down
5 changes: 3 additions & 2 deletions include/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <glib.h>

void string_remove_at(char *str, size_t pos);
gchar *string_insert_chars_at(gchar *str, gchar *chars, size_t pos);
glong string_get_nb_bytes_until(gchar *str, glong until);
gchar *string_remove_at(char *str, glong pos);
gchar *string_insert_chars_at(gchar *str, gchar *chars, glong pos);
void pixel_data_print(guint32 pixel);
15 changes: 10 additions & 5 deletions src/paint.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ static void cursor_move_backward(struct swappy_paint_text *text) {
}

static void cursor_move_forward(struct swappy_paint_text *text) {
if (text->cursor < strlen(text->text)) {
if (text->cursor < g_utf8_strlen(text->text, -1)) {
text->cursor++;
}
}
Expand Down Expand Up @@ -194,6 +194,7 @@ void paint_update_temporary_text(struct swappy_state *state,
GdkEventKey *event) {
struct swappy_paint *paint = state->temp_paint;
struct swappy_paint_text *text;
char *new_text;
char buffer[32];
guint32 unicode;

Expand All @@ -209,14 +210,18 @@ void paint_update_temporary_text(struct swappy_state *state,
paint_commit_temporary(state);
break;
case GDK_KEY_BackSpace:
if (strlen(text->text) > 0) {
string_remove_at(text->text, text->cursor - 1);
if (g_utf8_strlen(text->text, -1) > 0) {
new_text = string_remove_at(text->text, text->cursor - 1);
g_free(text->text);
text->text = new_text;
cursor_move_backward(text);
}
break;
case GDK_KEY_Delete:
if (strlen(text->text) > 0) {
string_remove_at(text->text, text->cursor);
if (g_utf8_strlen(text->text, -1) > 0) {
new_text = string_remove_at(text->text, text->cursor);
g_free(text->text);
text->text = new_text;
}
break;
case GDK_KEY_Left:
Expand Down
8 changes: 6 additions & 2 deletions src/render.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include "algebra.h"
#include "swappy.h"
#include "util.h"

#define pango_layout_t PangoLayout
#define pango_font_description_t PangoFontDescription
Expand Down Expand Up @@ -197,17 +198,20 @@ static void render_text(cairo_t *cr, struct swappy_paint_text text) {
pango_layout_set_width(layout, pango_units_from_double(w));
pango_layout_set_font_description(layout, desc);
pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);

gint count = pango_layout_get_character_count(layout);

pango_font_description_free(desc);

if (text.mode == SWAPPY_TEXT_MODE_EDIT) {
pango_rectangle_t strong_pos;
pango_rectangle_t weak_pos;
struct swappy_box cursor_box;
cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 0.3);
cairo_set_line_width(cr, 5);
cairo_rectangle(cr, x, y, w, h);
cairo_stroke(cr);
pango_layout_get_cursor_pos(layout, text.cursor, &strong_pos, &weak_pos);
glong bytes_til_cursor = string_get_nb_bytes_until(text.text, text.cursor);
pango_layout_get_cursor_pos(layout, bytes_til_cursor, &strong_pos, NULL);
convert_pango_rectangle_to_swappy_box(strong_pos, &cursor_box);
cairo_move_to(crt, cursor_box.x, cursor_box.y);
cairo_set_source_rgba(crt, 0.3, 0.3, 0.3, 1);
Expand Down
70 changes: 49 additions & 21 deletions src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,68 @@
#include <glib.h>
#include <string.h>

void string_remove_at(gchar *str, size_t pos) {
if (str && strlen(str) > pos) {
memmove(&str[pos], &str[pos + 1], strlen(str) - pos);
gchar *string_remove_at(gchar *str, glong pos) {
glong str_len = g_utf8_strlen(str, -1);
gchar *new_str = g_new0(gchar, MAX(str_len - 1, 1));
gchar *buffer_source = str;
gchar *buffer_copy = new_str;
glong i = 0;
gint bytes;
gunichar c;

if (pos <= str_len && g_utf8_validate(str, -1, NULL)) {
while (*buffer_source != '\0') {
c = g_utf8_get_char(buffer_source);
buffer_source = g_utf8_next_char(buffer_source);
if (i != pos) {
bytes = g_unichar_to_utf8(c, buffer_copy);
buffer_copy += bytes;
}
i++;
}
}

return new_str;
}

gchar *string_insert_chars_at(gchar *str, gchar *chars, size_t pos) {
gchar *new_str;
gchar *string_insert_chars_at(gchar *str, gchar *chars, glong pos) {
gchar *new_str = NULL;

if (str && chars) {
size_t n = strlen(str);
size_t m = strlen(chars);
size_t i = 0, j = 0;

new_str = g_new(gchar, n + m + 1);

while (j < n + m) {
if (j == pos) {
for (size_t k = 0; k < m; k++) {
new_str[j++] = chars[k];
}
} else {
new_str[j++] = str[i++];
}
glong str_len = g_utf8_strlen(str, -1);

if (pos == 0) {
new_str = g_strconcat(chars, NULL);
} else if (pos == str_len) {
new_str = g_strconcat(str, chars, NULL);
} else if (pos > 0 && pos < str_len) {
gchar *from = g_new0(gchar, pos);
gchar *end = g_utf8_offset_to_pointer(str, pos);

g_utf8_strncpy(from, str, pos);
new_str = g_strconcat(from, chars, end, NULL);

g_free(from);
}

new_str[j] = '\0';
} else {
new_str = NULL;
new_str = g_new0(gchar, 1);
}

return new_str;
}

glong string_get_nb_bytes_until(gchar *str, glong until) {
glong ret = 0;
if (str) {
gchar *sub = g_utf8_substring(str, 0, until);
ret = strlen(sub);
g_free(sub);
}

return ret;
}

void pixel_data_print(guint32 pixel) {
const guint32 r = pixel >> 24 & 0xff;
const guint32 g = pixel >> 16 & 0xff;
Expand Down

0 comments on commit d8550b2

Please sign in to comment.