Compare commits

...

5 Commits

Author SHA1 Message Date
Matthias Clasen
729b423613 Emoji: Make search case-insensitive
Translated names are inevitable going to have some capitalization,
so be prepared to ignore it when searching.
2017-08-27 17:10:28 -04:00
Matthias Clasen
ff5d2b2d0b Translate emoji names
Display translated names, and match against translated
names when searching.
2017-08-27 16:53:09 -04:00
Matthias Clasen
c63bd813f7 Extract emoji names for translation 2017-08-27 16:52:55 -04:00
Matthias Clasen
2662129448 emoji: Add a preview to the chooser
This lets us show just the current emoji in a bigger size,
and also lets us show the name, so users can learn what
to search for.
2017-08-27 16:08:34 -04:00
Matthias Clasen
b44856a3cb meson: Make sure ENABLE_NLS is actually defined
Despite the comment, we ended up without ENABLE_NLS.
2017-08-27 16:08:34 -04:00
7 changed files with 1794 additions and 165 deletions

View File

@@ -1,7 +1,7 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* always defined to indicate that i18n is enabled */
#mesondefine ENABLE_NLS
#define ENABLE_NLS 1
/* The prefix for our gettext translation domains. */
#mesondefine GETTEXT_PACKAGE

View File

@@ -102,10 +102,11 @@ main (int argc, char *argv[])
GBytes *bytes;
GHashTable *names;
GString *name_key;
GString *name_header;
if (argc != 4)
if (argc != 5)
{
g_print ("Usage: emoji-convert INPUT INPUT1 OUTPUT\n");
g_print ("Usage: emoji-convert INPUT1 INPUT2 OUTPUT1 OUTPUT2\n");
return 1;
}
@@ -124,6 +125,8 @@ main (int argc, char *argv[])
names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
name_key = g_string_new ("");
name_header = g_string_new ("#if 0\n\n");
while (json_object_iter_next (&iter, &name, &node))
{
JsonObject *obj = json_node_get_object (node);
@@ -216,6 +219,7 @@ main (int argc, char *argv[])
shortname = g_hash_table_lookup (names, name_key->str);
g_variant_builder_add (&builder, "(auss)", &b1, name, shortname ? shortname : "");
g_string_append_printf (name_header, "NC_(\"emoji name\", \"%s\")\n", name);
}
v = g_variant_builder_end (&builder);
@@ -226,5 +230,12 @@ main (int argc, char *argv[])
return 1;
}
g_string_append (name_header, "\n\n#endif\n");
if (!g_file_set_contents (argv[4], name_header->str, name_header->len, &error))
{
g_error ("%s", error->message);
return 1;
}
return 0;
}

1521
gtk/emoji/emoji.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -61,6 +61,9 @@ struct _GtkEmojiChooser
EmojiSection symbols;
EmojiSection flags;
GtkWidget *emoji_preview;
GtkWidget *emoji_name_preview;
GtkGesture *recent_press;
GtkGesture *people_press;
GtkGesture *body_press;
@@ -118,10 +121,11 @@ scroll_to_section (GtkButton *button,
}
static void
add_emoji (GtkWidget *box,
gboolean prepend,
GVariant *item,
gunichar modifier);
add_emoji (GtkEmojiChooser *chooser,
GtkWidget *box,
gboolean prepend,
GVariant *item,
gunichar modifier);
#define MAX_RECENT (7*3)
@@ -141,7 +145,7 @@ populate_recent_section (GtkEmojiChooser *chooser)
emoji_data = g_variant_get_child_value (item, 0);
g_variant_get_child (item, 1, "u", &modifier);
add_emoji (chooser->recent.box, FALSE, emoji_data, modifier);
add_emoji (chooser, chooser->recent.box, FALSE, emoji_data, modifier);
g_variant_unref (emoji_data);
g_variant_unref (item);
}
@@ -184,7 +188,7 @@ add_recent_item (GtkEmojiChooser *chooser,
}
g_list_free (children);
add_emoji (chooser->recent.box, TRUE, item, modifier);
add_emoji (chooser, chooser->recent.box, TRUE, item, modifier);
g_settings_set_value (chooser->settings, "recent-emoji", g_variant_builder_end (&builder));
@@ -221,6 +225,7 @@ long_pressed_cb (GtkGesture *gesture,
double y,
gpointer data)
{
GtkEmojiChooser *chooser = data;
GtkWidget *child;
GtkWidget *popover;
GtkWidget *view;
@@ -272,24 +277,19 @@ long_pressed_cb (GtkGesture *gesture,
g_signal_connect (box, "child-activated", G_CALLBACK (emoji_activated), parent_popover);
add_emoji (box, FALSE, emoji_data, 0);
add_emoji (chooser, box, FALSE, emoji_data, 0);
for (modifier = 0x1f3fb; modifier <= 0x1f3ff; modifier++)
add_emoji (box, FALSE, emoji_data, modifier);
add_emoji (chooser, box, FALSE, emoji_data, modifier);
gtk_popover_popup (GTK_POPOVER (popover));
}
static void
add_emoji (GtkWidget *box,
gboolean prepend,
GVariant *item,
gunichar modifier)
codes_to_utf8 (GVariant *item,
gunichar modifier,
char text[])
{
GtkWidget *child;
GtkWidget *label;
PangoAttrList *attrs;
GVariant *codes;
char text[64];
char *p = text;
int i;
@@ -305,7 +305,54 @@ add_emoji (GtkWidget *box,
p += g_unichar_to_utf8 (code, p);
}
p[0] = 0;
}
static gboolean
enter_or_leave (GtkWidget *child,
GdkEventCrossing *event,
gpointer data)
{
GtkEmojiChooser *chooser = data;
if (gdk_event_get_event_type ((GdkEvent *)event) == GDK_ENTER_NOTIFY)
{
GVariant *emoji_data;
gunichar modifier;
const char *name;
const char *translated;
char text[64];
emoji_data = (GVariant*) g_object_get_data (G_OBJECT (child), "emoji-data");
modifier = (gunichar) GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (child), "modifier"));
g_variant_get_child (emoji_data, 1, "&s", &name);
translated = g_dpgettext2 (GETTEXT_PACKAGE, "emoji name", name);
codes_to_utf8 (emoji_data, modifier, text);
gtk_label_set_text (GTK_LABEL (chooser->emoji_preview), text);
gtk_label_set_text (GTK_LABEL (chooser->emoji_name_preview), translated);
}
else
{
gtk_label_set_text (GTK_LABEL (chooser->emoji_preview), "");
gtk_label_set_text (GTK_LABEL (chooser->emoji_name_preview), "");
}
return GDK_EVENT_PROPAGATE;
}
static void
add_emoji (GtkEmojiChooser *chooser,
GtkWidget *box,
gboolean prepend,
GVariant *item,
gunichar modifier)
{
GtkWidget *child;
GtkWidget *label;
PangoAttrList *attrs;
char text[64];
codes_to_utf8 (item, modifier, text);
label = gtk_label_new (text);
attrs = pango_attr_list_new ();
pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_X_LARGE));
@@ -322,6 +369,9 @@ add_emoji (GtkWidget *box,
gtk_container_add (GTK_CONTAINER (child), label);
gtk_flow_box_insert (GTK_FLOW_BOX (box), child, prepend ? 0 : -1);
g_signal_connect (child, "enter-notify-event", G_CALLBACK (enter_or_leave), chooser);
g_signal_connect (child, "leave-notify-event", G_CALLBACK (enter_or_leave), chooser);
}
static void
@@ -360,7 +410,7 @@ populate_emoji_chooser (GtkEmojiChooser *chooser)
else if (strcmp (name, chooser->flags.first) == 0)
box = chooser->flags.box;
add_emoji (box, FALSE, item, 0);
add_emoji (chooser, box, FALSE, item, 0);
}
g_bytes_unref (bytes);
@@ -409,12 +459,15 @@ filter_func (GtkFlowBoxChild *child,
GVariant *emoji_data;
const char *text;
const char *name;
char *cf_text;
char *cf_name;
gboolean res;
res = TRUE;
chooser = GTK_EMOJI_CHOOSER (gtk_widget_get_ancestor (GTK_WIDGET (child), GTK_TYPE_EMOJI_CHOOSER));
text = gtk_entry_get_text (GTK_ENTRY (chooser->search_entry));
emoji_data = (GVariant *) g_object_get_data (G_OBJECT (child), "emoji-data");
if (text[0] == 0)
@@ -424,7 +477,13 @@ filter_func (GtkFlowBoxChild *child,
goto out;
g_variant_get_child (emoji_data, 1, "&s", &name);
res = strstr (name, text) != NULL;
name = g_dpgettext2 (GETTEXT_PACKAGE, "emoji name", name);
cf_text = g_utf8_casefold (text, -1);
cf_name = g_utf8_casefold (name, -1);
res = strstr (cf_name, cf_text) != NULL;
g_free (cf_text);
g_free (cf_name);
out:
if (res)
@@ -620,6 +679,9 @@ gtk_emoji_chooser_class_init (GtkEmojiChooserClass *klass)
gtk_widget_class_bind_template_child (widget_class, GtkEmojiChooser, flags.heading);
gtk_widget_class_bind_template_child (widget_class, GtkEmojiChooser, flags.button);
gtk_widget_class_bind_template_child (widget_class, GtkEmojiChooser, emoji_preview);
gtk_widget_class_bind_template_child (widget_class, GtkEmojiChooser, emoji_name_preview);
gtk_widget_class_bind_template_callback (widget_class, emoji_activated);
gtk_widget_class_bind_template_callback (widget_class, search_changed);
}

View File

@@ -4411,11 +4411,17 @@ button.emoji-section:backdrop { color: $backdrop_borders_color; }
button.emoji-section:backdrop:checked { color: $backdrop_fg_color; }
.emoji {
font-size: x-large;
padding: 6px;
border-radius: 6px;
font-size: small;
padding: 4px;
border-radius: 4px;
}
.emoji:hover {
background: $selected_bg_color;
}
.preview .emoji:hover,
.preview .emoji {
font-size: xx-large;
background: none;
}

View File

@@ -18,147 +18,6 @@
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="vexpand">1</property>
<property name="hscrollbar-policy">never</property>
<property name="min-content-height">250</property>
<style>
<class name="view"/>
</style>
<child>
<object class="GtkBox" id="emoji_box">
<property name="orientation">vertical</property>
<property name="margin">6</property>
<property name="spacing">6</property>
<child>
<object class="GtkFlowBox" id="recent.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="people.heading">
<property name="label" translatable="yes" context="emoji category">Smileys &amp; People</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="people.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="body.heading">
<property name="label" translatable="yes" context="emoji category">Body &amp; Clothing</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="body.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="nature.heading">
<property name="label" translatable="yes" context="emoji category">Animals &amp; Nature</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="nature.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="food.heading">
<property name="label" translatable="yes" context="emoji category">Food &amp; Drink</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="food.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="travel.heading">
<property name="label" translatable="yes" context="emoji category">Travel &amp; Places</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="travel.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="activities.heading">
<property name="label" translatable="yes" context="emoji category">Activities</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="activities.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="objects.heading">
<property name="label" translatable="yes" context="emoji category">Objects</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="objects.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="symbols.heading">
<property name="label" translatable="yes" context="emoji category">Symbols</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="symbols.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="flags.heading">
<property name="label" translatable="yes" context="emoji category">Flags</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="flags.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<child>
@@ -243,6 +102,175 @@
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="vexpand">1</property>
<property name="hscrollbar-policy">never</property>
<property name="min-content-height">250</property>
<style>
<class name="view"/>
</style>
<child>
<object class="GtkBox" id="emoji_box">
<property name="orientation">vertical</property>
<property name="margin">6</property>
<property name="spacing">6</property>
<child>
<object class="GtkFlowBox" id="recent.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<property name="max-children-per-line">10</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="people.heading">
<property name="label" translatable="yes" context="emoji category">Smileys &amp; People</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="people.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<property name="max-children-per-line">10</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="body.heading">
<property name="label" translatable="yes" context="emoji category">Body &amp; Clothing</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="body.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<property name="max-children-per-line">10</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="nature.heading">
<property name="label" translatable="yes" context="emoji category">Animals &amp; Nature</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="nature.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<property name="max-children-per-line">10</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="food.heading">
<property name="label" translatable="yes" context="emoji category">Food &amp; Drink</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="food.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<property name="max-children-per-line">10</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="travel.heading">
<property name="label" translatable="yes" context="emoji category">Travel &amp; Places</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="travel.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<property name="max-children-per-line">10</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="activities.heading">
<property name="label" translatable="yes" context="emoji category">Activities</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="activities.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<property name="max-children-per-line">10</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="objects.heading">
<property name="label" translatable="yes" context="emoji category">Objects</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="objects.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<property name="max-children-per-line">10</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="symbols.heading">
<property name="label" translatable="yes" context="emoji category">Symbols</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="symbols.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<property name="max-children-per-line">10</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
<child>
<object class="GtkLabel" id="flags.heading">
<property name="label" translatable="yes" context="emoji category">Flags</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkFlowBox" id="flags.box">
<property name="homogeneous">1</property>
<property name="selection-mode">none</property>
<property name="max-children-per-line">10</property>
<signal name="child-activated" handler="emoji_activated"/>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<style>
<class name="preview"/>
</style>
<child>
<object class="GtkLabel" id="emoji_preview">
<style>
<class name="emoji"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="emoji_name_preview">
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">list</property>

View File

@@ -41,6 +41,7 @@ gtk/a11y/gtkrenderercellaccessible.c
gtk/a11y/gtkscalebuttonaccessible.c
gtk/a11y/gtkspinneraccessible.c
gtk/a11y/gtkswitchaccessible.c
gtk/emoji/emoji.h
gtk/encodesymbolic.c
gtk/gtkaboutdialog.c
gtk/gtkaccelgroup.c