[gtk+/wip/matthiasc/emoji-picker] better styling



commit 5c25b0d755219e8f4abf7e2b2e7ec74aeeb04057
Author: Matthias Clasen <mclasen redhat com>
Date:   Thu Aug 10 21:33:35 2017 -0400

    better styling
    
    This is Lapo-grade refinement for the picker styling.

 tests/gtkemojipicker.c   |  509 ++++++++++++++++++++++++----------------------
 tests/gtkemojipicker.css |   74 +++++--
 tests/gtkemojipicker.h   |    2 +-
 tests/gtkemojipicker.ui  |  150 ++++----------
 4 files changed, 371 insertions(+), 364 deletions(-)
---
diff --git a/tests/gtkemojipicker.c b/tests/gtkemojipicker.c
index 256120a..e358226 100644
--- a/tests/gtkemojipicker.c
+++ b/tests/gtkemojipicker.c
@@ -3,6 +3,15 @@
 
 #include "gtkemojipicker.h"
 
+typedef struct {
+        GtkWidget *box;
+        GtkWidget *heading;
+        GtkWidget *button;
+
+        const char *first;
+        gunichar label;
+} EmojiSection;
+
 struct _GtkEmojiPicker
 {
         GtkPopover parent_instance;
@@ -10,54 +19,22 @@ struct _GtkEmojiPicker
         GtkWidget *scrolled_window;
         GtkWidget *search_entry;
 
-        GtkWidget *people_box;
-        GtkWidget *people_heading;
-        GtkWidget *people_button;
-        GtkWidget *people_label;
-
-        GtkWidget *body_box;
-        GtkWidget *body_heading;
-        GtkWidget *body_button;
-        GtkWidget *body_label;
-
-        GtkWidget *nature_box;
-        GtkWidget *nature_heading;
-        GtkWidget *nature_button;
-        GtkWidget *nature_label;
-
-        GtkWidget *food_box;
-        GtkWidget *food_heading;
-        GtkWidget *food_button;
-        GtkWidget *food_label;
-
-        GtkWidget *travel_box;
-        GtkWidget *travel_heading;
-        GtkWidget *travel_button;
-        GtkWidget *travel_label;
-
-        GtkWidget *activities_box;
-        GtkWidget *activities_heading;
-        GtkWidget *activities_button;
-        GtkWidget *activities_label;
-
-        GtkWidget *objects_box;
-        GtkWidget *objects_heading;
-        GtkWidget *objects_button;
-        GtkWidget *objects_label;
-
-        GtkWidget *symbols_box;
-        GtkWidget *symbols_heading;
-        GtkWidget *symbols_button;
-        GtkWidget *symbols_label;
-
-        GtkWidget *flags_box;
-        GtkWidget *flags_heading;
-        GtkWidget *flags_button;
-        GtkWidget *flags_label;
-
-        GtkWidget *scroll_to_button;
+        EmojiSection recent;
+        EmojiSection people;
+        EmojiSection body;
+        EmojiSection nature;
+        EmojiSection food;
+        EmojiSection travel;
+        EmojiSection activities;
+        EmojiSection objects;
+        EmojiSection symbols;
+        EmojiSection flags;
 
+        EmojiSection *scroll_to_section;
+
+        GtkGesture *recent_press;
         GtkGesture *people_press;
+        GtkGesture *body_press;
 
         GVariant *data;
 };
@@ -85,35 +62,14 @@ static gboolean
 scroll_in_idle (gpointer data)
 {
         GtkEmojiPicker *picker = data;
-        GtkWidget *heading;
         GtkAdjustment *adj;
-        GtkAllocation alloc;
+        GtkAllocation alloc = { 0, 0, 0, 0 };
         double page_increment, value;
         gboolean dummy;
 
-        if (picker->scroll_to_button == picker->people_button)
-                heading = picker->people_heading;
-        else if (picker->scroll_to_button == picker->body_button)
-                heading = picker->body_heading;
-        else if (picker->scroll_to_button == picker->nature_button)
-                heading = picker->nature_heading;
-        else if (picker->scroll_to_button == picker->food_button)
-                heading = picker->food_heading;
-        else if (picker->scroll_to_button == picker->travel_button)
-                heading = picker->travel_heading;
-        else if (picker->scroll_to_button == picker->activities_button)
-                heading = picker->activities_heading;
-        else if (picker->scroll_to_button == picker->objects_button)
-                heading = picker->objects_heading;
-        else if (picker->scroll_to_button == picker->symbols_button)
-                heading = picker->symbols_heading;
-        else if (picker->scroll_to_button == picker->flags_button)
-                heading = picker->flags_heading;
-        else
-                return G_SOURCE_REMOVE;
-
         adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (picker->scrolled_window));
-        gtk_widget_get_allocation (heading, &alloc);
+        if (picker->scroll_to_section->heading)
+                gtk_widget_get_allocation (picker->scroll_to_section->heading, &alloc);
         page_increment = gtk_adjustment_get_page_increment (adj);
         value = gtk_adjustment_get_value (adj);
         gtk_adjustment_set_page_increment (adj, alloc.y - value);
@@ -127,13 +83,59 @@ static void
 scroll_to_section (GtkButton *button,
                    gpointer   data)
 {
-        GtkWidget *widget = GTK_WIDGET (button);
-        GtkEmojiPicker *picker = data;
+        EmojiSection *section = data;
+        GtkEmojiPicker *picker;
+
+        picker = GTK_EMOJI_PICKER (gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_EMOJI_PICKER));
+
+        if (picker->scroll_to_section == section)
+                return;
+
+        picker->scroll_to_section = section;
+        g_idle_add (scroll_in_idle, picker);
+}
+
+static void
+add_emoji (GtkWidget    *box,
+           gboolean      prepend,
+           GVariantIter *iter,
+           GVariant     *data);
+
+#define MAX_RECENT 24444
+
+static void
+add_recent_item (GtkEmojiPicker *picker,
+                 GVariant       *item)
+{
+        GList *children, *l;
+        GVariantIter *codes;
+        const char *name;
+        int i;
+
+        g_variant_ref (item);
+
+        g_variant_get_child (item, 1, "&s", &name);
+
+        children = gtk_container_get_children (GTK_CONTAINER (picker->recent.box));
+        for (l = children, i = 1; l; l = l->next, i++) {
+                GVariant *item2 = g_object_get_data (G_OBJECT (l->data), "emoji-data");
+                const char *name2;
 
-        if (picker->scroll_to_button != widget) {
-                picker->scroll_to_button = widget;
-                g_idle_add (scroll_in_idle, picker);
+                g_variant_get_child (item2, 1, "&s", &name2);
+                if (strcmp (name, name2) == 0) {
+                        gtk_widget_destroy (GTK_WIDGET (l->data));
+                        i--;
+                }
+                if (i >= MAX_RECENT)
+                        gtk_widget_destroy (GTK_WIDGET (l->data));
         }
+        g_list_free (children);
+
+        g_variant_get_child (item, 0, "au", &codes);
+        add_emoji (picker->recent.box, TRUE, codes, item);
+        g_variant_iter_free (codes);
+
+        g_variant_unref (item);
 }
 
 static void
@@ -141,28 +143,29 @@ emoji_activated (GtkFlowBox      *box,
                  GtkFlowBoxChild *child,
                  gpointer         data)
 {
-        const char *text;
+        GtkEmojiPicker *picker = data;
+        char *text;
         GtkWidget *label;
+        GVariant *item;
 
-        gtk_popover_popdown (GTK_POPOVER (data));
+        gtk_popover_popdown (GTK_POPOVER (picker));
 
         label = gtk_bin_get_child (GTK_BIN (child));
-        text = gtk_label_get_label (GTK_LABEL (label));
+        text = g_strdup (gtk_label_get_label (GTK_LABEL (label)));
+
+        item = (GVariant*) g_object_get_data (G_OBJECT (child), "emoji-data");
+        add_recent_item (picker, item);
+
         g_signal_emit (data, signals[ACTIVATED], 0, text);
+        g_free (text);
 }
 
 static void
-add_emoji (GtkWidget    *box,
-           GVariantIter *iter,
-           GVariant     *data);
-
-static void
-people_pressed_cb (GtkGesture *gesture,
-                   double x,
-                   double y,
-                   gpointer data)
+long_pressed_cb (GtkGesture *gesture,
+                 double      x,
+                 double      y,
+                 gpointer    data)
 {
-        GtkEmojiPicker *picker = data;
         GtkWidget *child;
         GtkWidget *popover;
         GtkWidget *view;
@@ -172,7 +175,8 @@ people_pressed_cb (GtkGesture *gesture,
         GVariantIter *iter;
         GVariantIter *codes;
 
-        child = GTK_WIDGET (gtk_flow_box_get_child_at_pos (GTK_FLOW_BOX (picker->people_box), x, y));
+        box = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
+        child = GTK_WIDGET (gtk_flow_box_get_child_at_pos (GTK_FLOW_BOX (box), x, y));
         if (!child)
                 return;
 
@@ -202,10 +206,10 @@ people_pressed_cb (GtkGesture *gesture,
         g_signal_connect (box, "child-activated", G_CALLBACK (emoji_activated), parent_popover);
 
         g_variant_get_child (emoji_data, 0, "au", &codes);
-        add_emoji (box, codes, NULL);
+        add_emoji (box, FALSE, codes, emoji_data);
         g_variant_iter_free (codes);
         while (g_variant_iter_next (iter, "au", &codes)) {
-                add_emoji (box, codes, NULL);
+                add_emoji (box, FALSE, codes, emoji_data);
                 g_variant_iter_free (codes);
         }
 
@@ -214,6 +218,7 @@ people_pressed_cb (GtkGesture *gesture,
 
 static void
 add_emoji (GtkWidget    *box,
+           gboolean      prepend,
            GVariantIter *iter,
            GVariant     *data)
 {
@@ -236,26 +241,12 @@ add_emoji (GtkWidget    *box,
 
         child = gtk_flow_box_child_new ();
         gtk_style_context_add_class (gtk_widget_get_style_context (child), "emoji");
-        if (data)
-                g_object_set_data_full (G_OBJECT (child), "emoji-data",
-                                        g_variant_ref (data),
-                                        (GDestroyNotify)g_variant_unref);
+        g_object_set_data_full (G_OBJECT (child), "emoji-data",
+                                g_variant_ref (data),
+                                (GDestroyNotify)g_variant_unref);
 
         gtk_container_add (GTK_CONTAINER (child), label);
-        gtk_container_add (GTK_CONTAINER (box), child);
-}
-
-static void
-set_label (GtkWidget *label, gunichar code)
-{
-        char text[14];
-        char *p;
-
-        p = text;
-        p += g_unichar_to_utf8 (code, p);
-        p += g_unichar_to_utf8 (0xfe0e, p);
-        p[0] = 0;
-        gtk_label_set_label (GTK_LABEL (label), text);
+        gtk_flow_box_insert (GTK_FLOW_BOX (box), child, prepend ? 0 : -1);
 }
 
 static void
@@ -265,7 +256,7 @@ populate_emoji_picker (GtkEmojiPicker *picker)
         g_autoptr(GBytes) bytes = NULL;
         GVariantIter iter;
         GVariant *item;
-        int i;
+        GtkWidget *box;
 
         file = g_mapped_file_new ("emoji.data", FALSE, NULL);
         if (!file)
@@ -275,58 +266,49 @@ populate_emoji_picker (GtkEmojiPicker *picker)
         picker->data = g_variant_ref_sink (g_variant_new_from_bytes (G_VARIANT_TYPE ("a(ausaau)"), bytes, 
TRUE));
 
         g_variant_iter_init (&iter, picker->data);
-        i = 0;
+        box = picker->people.box;
         while ((item = g_variant_iter_next_value (&iter))) {
                 GVariantIter *codes;
-                GtkWidget *box;
-
-                if (i <= 297)
-                        box = picker->people_box;
-                else if (i <= 446)
-                        box = picker->body_box;
-                else if (i <= 559)
-                        box = picker->nature_box;
-                else if (i <= 661)
-                        box = picker->food_box;
-                else if (i <= 868)
-                        box = picker->travel_box;
-                else if (i <= 928)
-                        box = picker->activities_box;
-                else if (i <= 1090)
-                        box = picker->objects_box;
-                else if (i <= 1295)
-                        box = picker->symbols_box;
-                else
-                        box = picker->flags_box;
+                const char *name;
 
                 g_variant_get_child (item, 0, "au", &codes);
-                add_emoji (box, codes, item);
+                g_variant_get_child (item, 1, "&s", &name);
+
+                if (strcmp (name, picker->body.first) == 0)
+                        box = picker->body.box;
+                else if (strcmp (name, picker->nature.first) == 0)
+                        box = picker->nature.box;
+                else if (strcmp (name, picker->food.first) == 0)
+                        box = picker->food.box;
+                else if (strcmp (name, picker->travel.first) == 0)
+                        box = picker->travel.box;
+                else if (strcmp (name, picker->activities.first) == 0)
+                        box = picker->activities.box;
+                else if (strcmp (name, picker->objects.first) == 0)
+                        box = picker->objects.box;
+                else if (strcmp (name, picker->symbols.first) == 0)
+                        box = picker->symbols.box;
+                else if (strcmp (name, picker->flags.first) == 0)
+                        box = picker->flags.box;
+
+                add_emoji (box, FALSE, codes, item);
                 g_variant_iter_free (codes);
-
-                i++;
         }
 
-        set_label (picker->people_label, 0x1f642);
-        set_label (picker->body_label, 0x1f44d);
-        set_label (picker->nature_label, 0x1f337);
-        set_label (picker->food_label, 0x1f374);
-        set_label (picker->travel_label, 0x2708);
-        set_label (picker->activities_label, 0x1f3c3);
-        set_label (picker->objects_label, 0x1f514);
-        set_label (picker->symbols_label, 0x2764);
-        set_label (picker->flags_label, 0x1f3f4);
 }
 
 static void
-update_state (GtkWidget *heading, GtkWidget *button, double value)
+update_state (EmojiSection *section, double value)
 {
-        GtkAllocation alloc;
+        GtkAllocation alloc = { 0, 0, 0, 20 };
+
+        if (section->heading)
+                gtk_widget_get_allocation (section->heading, &alloc);
 
-        gtk_widget_get_allocation (heading, &alloc);
         if (alloc.y <= value && value < alloc.y + alloc.height)
-                gtk_widget_set_state_flags (button, GTK_STATE_FLAG_CHECKED, FALSE);
+                gtk_widget_set_state_flags (section->button, GTK_STATE_FLAG_CHECKED, FALSE);
         else
-                gtk_widget_unset_state_flags (button, GTK_STATE_FLAG_CHECKED);
+                gtk_widget_unset_state_flags (section->button, GTK_STATE_FLAG_CHECKED);
 }
 
 static void
@@ -335,40 +317,56 @@ adj_value_changed (GtkAdjustment *adj, gpointer data)
         GtkEmojiPicker *picker = data;
         double value = gtk_adjustment_get_value (adj);
 
-        update_state (picker->people_heading, picker->people_button, value);
-        update_state (picker->body_heading, picker->body_button, value);
-        update_state (picker->nature_heading, picker->nature_button, value);
-        update_state (picker->food_heading, picker->food_button, value);
-        update_state (picker->travel_heading, picker->travel_button, value);
-        update_state (picker->activities_heading, picker->activities_button, value);
-        update_state (picker->objects_heading, picker->objects_button, value);
-        update_state (picker->symbols_heading, picker->symbols_button, value);
-        update_state (picker->flags_heading, picker->flags_button, value);
+        update_state (&picker->recent, value);
+        update_state (&picker->people, value);
+        update_state (&picker->body, value);
+        update_state (&picker->nature, value);
+        update_state (&picker->food, value);
+        update_state (&picker->travel, value);
+        update_state (&picker->activities, value);
+        update_state (&picker->objects, value);
+        update_state (&picker->symbols, value);
+        update_state (&picker->flags, value);
 }
 
 static gboolean
 filter_func (GtkFlowBoxChild *child, gpointer data)
 {
-        GtkEmojiPicker *picker = data;
+        EmojiSection *section = data;
+        GtkEmojiPicker *picker;
         GVariant *emoji_data;
         const char *text;
         const char *name;
+        gboolean res;
+
+        res = TRUE;
 
+        picker = GTK_EMOJI_PICKER (gtk_widget_get_ancestor (GTK_WIDGET (child), GTK_TYPE_EMOJI_PICKER));
         text = gtk_entry_get_text (GTK_ENTRY (picker->search_entry));
         emoji_data = (GVariant *) g_object_get_data (G_OBJECT (child), "emoji-data");
 
         if (text[0] == 0 || text[1] == 0)
-                return TRUE;
+                goto out;
 
         if (!emoji_data)
-                return TRUE;
+                goto out;
 
         g_variant_get_child (emoji_data, 1, "&s", &name);
+        res = strstr (name, text) != NULL;
+
+out:
+        if (res && section->heading)
+                gtk_widget_show (section->heading);
 
-        if (strstr (name, text))
-                return TRUE;
+        return res;
+}
 
-        return FALSE;
+static void
+invalidate_section (EmojiSection *section)
+{
+        if (section->heading)
+                gtk_widget_hide (section->heading);
+        gtk_flow_box_invalidate_filter (GTK_FLOW_BOX (section->box));
 }
 
 static void
@@ -376,15 +374,41 @@ search_changed (GtkEntry *entry, gpointer data)
 {
         GtkEmojiPicker *picker = data;
 
-        gtk_flow_box_invalidate_filter (GTK_FLOW_BOX (picker->people_box));
-        gtk_flow_box_invalidate_filter (GTK_FLOW_BOX (picker->body_box));
-        gtk_flow_box_invalidate_filter (GTK_FLOW_BOX (picker->nature_box));
-        gtk_flow_box_invalidate_filter (GTK_FLOW_BOX (picker->food_box));
-        gtk_flow_box_invalidate_filter (GTK_FLOW_BOX (picker->travel_box));
-        gtk_flow_box_invalidate_filter (GTK_FLOW_BOX (picker->activities_box));
-        gtk_flow_box_invalidate_filter (GTK_FLOW_BOX (picker->objects_box));
-        gtk_flow_box_invalidate_filter (GTK_FLOW_BOX (picker->symbols_box));
-        gtk_flow_box_invalidate_filter (GTK_FLOW_BOX (picker->flags_box));
+        invalidate_section (&picker->recent);
+        invalidate_section (&picker->people);
+        invalidate_section (&picker->body);
+        invalidate_section (&picker->nature);
+        invalidate_section (&picker->food);
+        invalidate_section (&picker->travel);
+        invalidate_section (&picker->activities);
+        invalidate_section (&picker->objects);
+        invalidate_section (&picker->symbols);
+        invalidate_section (&picker->flags);
+}
+
+static void
+setup_section (GtkEmojiPicker *picker,
+               EmojiSection   *section,
+               const char     *first,
+               gunichar        label)
+{
+        char text[14];
+        char *p;
+        GtkAdjustment *adj;
+
+        section->first = first;
+
+        p = text;
+        p += g_unichar_to_utf8 (label, p);
+        p += g_unichar_to_utf8 (0xfe0e, p);
+        p[0] = 0;
+        gtk_button_set_label (GTK_BUTTON (section->button), text);
+
+        adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (picker->scrolled_window));
+
+        gtk_container_set_focus_vadjustment (GTK_CONTAINER (section->box), adj);
+        gtk_flow_box_set_filter_func (GTK_FLOW_BOX (section->box), filter_func, section, NULL);
+        g_signal_connect (section->button, "clicked", G_CALLBACK (scroll_to_section), section);
 }
 
 static void
@@ -395,8 +419,14 @@ gtk_emoji_picker_init (GtkEmojiPicker *picker)
 
         gtk_widget_init_template (GTK_WIDGET (picker));
 
-        picker->people_press = gtk_gesture_long_press_new (picker->people_box);
-        g_signal_connect (picker->people_press, "pressed", G_CALLBACK (people_pressed_cb), picker);
+        picker->recent_press = gtk_gesture_long_press_new (picker->recent.box);
+        g_signal_connect (picker->recent_press, "pressed", G_CALLBACK (long_pressed_cb), picker);
+
+        picker->people_press = gtk_gesture_long_press_new (picker->people.box);
+        g_signal_connect (picker->people_press, "pressed", G_CALLBACK (long_pressed_cb), picker);
+
+        picker->body_press = gtk_gesture_long_press_new (picker->body.box);
+        g_signal_connect (picker->body_press, "pressed", G_CALLBACK (long_pressed_cb), picker);
 
         provider = gtk_css_provider_new ();
         gtk_css_provider_load_from_path (provider, "gtkemojipicker.css");
@@ -405,30 +435,35 @@ gtk_emoji_picker_init (GtkEmojiPicker *picker)
                                                    GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
         g_object_unref (provider);
 
+        adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (picker->scrolled_window));
+        g_signal_connect (adj, "value-changed", G_CALLBACK (adj_value_changed), picker);
+
+        setup_section (picker, &picker->recent, NULL, 0x1f557);
+        setup_section (picker, &picker->people, "grinning face", 0x1f642);
+        setup_section (picker, &picker->body, "selfie", 0x1f44d);
+        setup_section (picker, &picker->nature, "monkey face", 0x1f337);
+        setup_section (picker, &picker->food, "grapes", 0x1f374);
+        setup_section (picker, &picker->travel, "globe showing Europe-Africa", 0x2708);
+        setup_section (picker, &picker->activities, "jack-o-lantern", 0x1f3c3);
+        setup_section (picker, &picker->objects, "muted speaker", 0x1f514);
+        setup_section (picker, &picker->symbols, "ATM sign", 0x2764);
+        setup_section (picker, &picker->flags, "chequered flag", 0x1f3f4);
+
         populate_emoji_picker (picker);
+}
+
+static void
+gtk_emoji_picker_show (GtkWidget *widget)
+{
+        GtkEmojiPicker *picker = GTK_EMOJI_PICKER (widget);
+        GtkAdjustment *adj;
 
         adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (picker->scrolled_window));
-        g_signal_connect (adj, "value-changed", G_CALLBACK (adj_value_changed), picker);
+        gtk_adjustment_set_value (adj, 0);
+
+        gtk_entry_set_text (GTK_ENTRY (picker->search_entry), "");
 
-        gtk_container_set_focus_vadjustment (GTK_CONTAINER (picker->people_box), adj);
-        gtk_container_set_focus_vadjustment (GTK_CONTAINER (picker->body_box), adj);
-        gtk_container_set_focus_vadjustment (GTK_CONTAINER (picker->nature_box), adj);
-        gtk_container_set_focus_vadjustment (GTK_CONTAINER (picker->food_box), adj);
-        gtk_container_set_focus_vadjustment (GTK_CONTAINER (picker->travel_box), adj);
-        gtk_container_set_focus_vadjustment (GTK_CONTAINER (picker->activities_box), adj);
-        gtk_container_set_focus_vadjustment (GTK_CONTAINER (picker->objects_box), adj);
-        gtk_container_set_focus_vadjustment (GTK_CONTAINER (picker->symbols_box), adj);
-        gtk_container_set_focus_vadjustment (GTK_CONTAINER (picker->flags_box), adj);
-
-        gtk_flow_box_set_filter_func (GTK_FLOW_BOX (picker->people_box), filter_func, picker, NULL);
-        gtk_flow_box_set_filter_func (GTK_FLOW_BOX (picker->body_box), filter_func, picker, NULL);
-        gtk_flow_box_set_filter_func (GTK_FLOW_BOX (picker->nature_box), filter_func, picker, NULL);
-        gtk_flow_box_set_filter_func (GTK_FLOW_BOX (picker->food_box), filter_func, picker, NULL);
-        gtk_flow_box_set_filter_func (GTK_FLOW_BOX (picker->travel_box), filter_func, picker, NULL);
-        gtk_flow_box_set_filter_func (GTK_FLOW_BOX (picker->activities_box), filter_func, picker, NULL);
-        gtk_flow_box_set_filter_func (GTK_FLOW_BOX (picker->objects_box), filter_func, picker, NULL);
-        gtk_flow_box_set_filter_func (GTK_FLOW_BOX (picker->symbols_box), filter_func, picker, NULL);
-        gtk_flow_box_set_filter_func (GTK_FLOW_BOX (picker->flags_box), filter_func, picker, NULL);
+        GTK_WIDGET_CLASS (gtk_emoji_picker_parent_class)->show (widget);
 }
 
 static void
@@ -440,6 +475,7 @@ gtk_emoji_picker_class_init (GtkEmojiPickerClass *klass)
         GBytes *bytes;
 
         object_class->finalize = gtk_emoji_picker_finalize;
+        widget_class->show = gtk_emoji_picker_show;
 
         signals[ACTIVATED] = g_signal_new ("activated",
                                            G_OBJECT_CLASS_TYPE (object_class),
@@ -458,58 +494,51 @@ gtk_emoji_picker_class_init (GtkEmojiPickerClass *klass)
         gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, scrolled_window);
         gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, search_entry);
 
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, people_box);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, people_heading);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, people_button);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, people_label);
-
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, body_box);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, body_heading);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, body_button);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, body_label);
-
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, nature_box);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, nature_heading);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, nature_button);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, nature_label);
-
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, food_box);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, food_heading);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, food_button);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, food_label);
-
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, travel_box);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, travel_heading);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, travel_button);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, travel_label);
-
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, activities_box);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, activities_heading);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, activities_button);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, activities_label);
-
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, objects_box);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, objects_heading);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, objects_button);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, objects_label);
-
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, symbols_box);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, symbols_heading);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, symbols_button);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, symbols_label);
-
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, flags_box);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, flags_heading);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, flags_button);
-        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, flags_label);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, recent.box);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, recent.button);
+
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, people.box);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, people.heading);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, people.button);
+
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, body.box);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, body.heading);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, body.button);
+
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, nature.box);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, nature.heading);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, nature.button);
+
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, food.box);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, food.heading);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, food.button);
+
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, travel.box);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, travel.heading);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, travel.button);
+
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, activities.box);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, activities.heading);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, activities.button);
+
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, objects.box);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, objects.heading);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, objects.button);
+
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, symbols.box);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, symbols.heading);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, symbols.button);
+
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, flags.box);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, flags.heading);
+        gtk_widget_class_bind_template_child (widget_class, GtkEmojiPicker, flags.button);
 
         gtk_widget_class_bind_template_callback (widget_class, emoji_activated);
-        gtk_widget_class_bind_template_callback (widget_class, scroll_to_section);
         gtk_widget_class_bind_template_callback (widget_class, search_changed);
 }
 
 GtkWidget *
 gtk_emoji_picker_new (void)
 {
-        return GTK_WIDGET (g_object_new (GTK_EMOJI_PICKER_TYPE, NULL));
+        return GTK_WIDGET (g_object_new (GTK_TYPE_EMOJI_PICKER, NULL));
 }
diff --git a/tests/gtkemojipicker.css b/tests/gtkemojipicker.css
index 6944624..4c9dbe7 100644
--- a/tests/gtkemojipicker.css
+++ b/tests/gtkemojipicker.css
@@ -1,28 +1,64 @@
-.emoji {
-  font-size: xx-large;
-  padding: 8px;
-  border-radius: 8px;
-}
+/* reset */
+button.emoji-section label { border-style: none; }
 
-.emoji:hover {
-  background: @theme_selected_bg_color;
-}
+/* starts here */
+popover.emoji-picker scrolledwindow undershoot.bottom { border-bottom: 1px solid @borders; }
+popover.emoji-picker scrolledwindow undershoot.bottom:backdrop { border-bottom: 1px solid 
@unfocused_borders; }
 
-button.emoji-section {
-  padding: 4px;
-}
+popover.emoji-picker scrolledwindow undershoot.top { border-top: 1px solid @borders; }
+popover.emoji-picker scrolledwindow undershoot.top:backdrop { border-top: 1px solid @unfocused_borders; }
 
-button.emoji-section:checked {
+popover.emoji-picker entry { margin-left: 2px; margin-right: 2px; margin-bottom: 2px; }
+
+popover.emoji-picker scrollbar.vertical.hovering trough { border-top: 1px solid @borders; border-bottom: 1px 
solid @borders; }
+popover.emoji-picker scrollbar.vertical.hovering trough:backdrop { border-top: 1px solid @unfocused_borders; 
border-bottom: 1px solid @unfocused_borders; }
+
+popover.emoji-picker { padding-left: 0; padding-right: 0; }
+
+button.emoji-section {
   border-color: transparent;
-  background: transparent;
+  border-width: 3px;
+  border-style: none none solid; 
+  border-radius: 0;
+
+  margin: 2px 4px 2px 4px;
+  padding: 3px 0 0;
+  min-width: 32px;
+  min-height: 28px;
+
+  /* reset props inherited from the button style */
+  background: none;
+  box-shadow: none;
+  text-shadow: none;
+
+  outline-offset: -5px;
 }
 
-button.emoji-section label {
-  border-color: transparent;
-  border-bottom: 2px solid transparent;
-  padding: 0 12px;
+button.emoji-section label { padding: 0; }
+
+button.emoji-section:hover { border-color: @borders; }
+
+button.emoji-section:checked { border-color: @theme_selected_bg_color; }
+
+button.emoji-section:backdrop:not(:checked) { border-color: transparent; }
+
+button.emoji-section { color: @borders; }
+
+button.emoji-section:hover { color: mix(@theme_fg_color, @borders, 0.5); }
+
+button.emoji-section:checked { color: @theme_fg_color; }
+
+button.emoji-section:backdrop { color: @unfocused_borders; }
+
+button.emoji-section:backdrop:checked { color: @theme_unfocused_fg_color; }
+
+.emoji {
+  font-size: x-large;
+  padding: 6px;
+  border-radius: 6px;
 }
 
-button.emoji-section:checked label {
-  border-bottom-color: @theme_selected_bg_color;
+.emoji:hover {
+  background: @theme_selected_bg_color;
 }
+
diff --git a/tests/gtkemojipicker.h b/tests/gtkemojipicker.h
index 8ef6e4a..d946f88 100644
--- a/tests/gtkemojipicker.h
+++ b/tests/gtkemojipicker.h
@@ -4,7 +4,7 @@
 
 G_BEGIN_DECLS
 
-#define GTK_EMOJI_PICKER_TYPE (gtk_emoji_picker_get_type ())
+#define GTK_TYPE_EMOJI_PICKER (gtk_emoji_picker_get_type ())
 
 G_DECLARE_FINAL_TYPE (GtkEmojiPicker, gtk_emoji_picker, GTK, EMOJI_PICKER, GtkPopover)
 
diff --git a/tests/gtkemojipicker.ui b/tests/gtkemojipicker.ui
index c822249..ff9f269 100644
--- a/tests/gtkemojipicker.ui
+++ b/tests/gtkemojipicker.ui
@@ -2,6 +2,9 @@
 <interface domain="gtk-3">
   <template class="GtkEmojiPicker" parent="GtkPopover">
     <property name="modal">1</property>
+    <style>
+      <class name="emoji-picker"/>
+    </style>
     <child>
       <object class="GtkBox" id="box">
         <property name="orientation">vertical</property>
@@ -25,159 +28,135 @@
                 <property name="margin">6</property>
                 <property name="spacing">6</property>
                 <child>
-                  <object class="GtkLabel" id="people_heading">
+                  <object class="GtkFlowBox" id="recent.box">
+                    <property name="homogeneous">1</property>
+                    <property name="selection-mode">none</property>
+                    <property name="activate-on-single-click">1</property>
+                    <signal name="child-activated" handler="emoji_activated"/>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="people.heading">
                     <property name="label" translatable="yes">Smileys &amp; People</property>
                     <property name="xalign">0</property>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkFlowBox" id="people_box">
+                  <object class="GtkFlowBox" id="people.box">
                     <property name="homogeneous">1</property>
                     <property name="selection-mode">none</property>
-                    <property name="min-children-per-line">6</property>
-                    <property name="max-children-per-line">6</property>
                     <property name="activate-on-single-click">1</property>
                     <signal name="child-activated" handler="emoji_activated"/>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="body_heading">
+                  <object class="GtkLabel" id="body.heading">
                     <property name="label" translatable="yes">Body &amp; Clothing</property>
                     <property name="xalign">0</property>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkFlowBox" id="body_box">
+                  <object class="GtkFlowBox" id="body.box">
                     <property name="homogeneous">1</property>
                     <property name="selection-mode">none</property>
-                    <property name="min-children-per-line">6</property>
-                    <property name="max-children-per-line">6</property>
                     <property name="activate-on-single-click">1</property>
                     <signal name="child-activated" handler="emoji_activated"/>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="nature_heading">
+                  <object class="GtkLabel" id="nature.heading">
                     <property name="label" translatable="yes">Animals &amp; Nature</property>
                     <property name="xalign">0</property>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkFlowBox" id="nature_box">
+                  <object class="GtkFlowBox" id="nature.box">
                     <property name="homogeneous">1</property>
                     <property name="selection-mode">none</property>
-                    <property name="row-spacing">6</property>
-                    <property name="column-spacing">6</property>
-                    <property name="min-children-per-line">6</property>
-                    <property name="max-children-per-line">6</property>
                     <property name="activate-on-single-click">1</property>
                     <signal name="child-activated" handler="emoji_activated"/>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="food_heading">
+                  <object class="GtkLabel" id="food.heading">
                     <property name="label" translatable="yes">Food &amp; Drink</property>
                     <property name="xalign">0</property>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkFlowBox" id="food_box">
+                  <object class="GtkFlowBox" id="food.box">
                     <property name="homogeneous">1</property>
                     <property name="selection-mode">none</property>
-                    <property name="row-spacing">6</property>
-                    <property name="column-spacing">6</property>
-                    <property name="min-children-per-line">6</property>
-                    <property name="max-children-per-line">6</property>
                     <property name="activate-on-single-click">1</property>
                     <signal name="child-activated" handler="emoji_activated"/>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="travel_heading">
+                  <object class="GtkLabel" id="travel.heading">
                     <property name="label" translatable="yes">Travel &amp; Places</property>
                     <property name="xalign">0</property>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkFlowBox" id="travel_box">
+                  <object class="GtkFlowBox" id="travel.box">
                     <property name="homogeneous">1</property>
                     <property name="selection-mode">none</property>
-                    <property name="row-spacing">6</property>
-                    <property name="column-spacing">6</property>
-                    <property name="min-children-per-line">6</property>
-                    <property name="max-children-per-line">6</property>
                     <property name="activate-on-single-click">1</property>
                     <signal name="child-activated" handler="emoji_activated"/>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="activities_heading">
+                  <object class="GtkLabel" id="activities.heading">
                     <property name="label" translatable="yes">Activities</property>
                     <property name="xalign">0</property>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkFlowBox" id="activities_box">
+                  <object class="GtkFlowBox" id="activities.box">
                     <property name="homogeneous">1</property>
                     <property name="selection-mode">none</property>
-                    <property name="row-spacing">6</property>
-                    <property name="column-spacing">6</property>
-                    <property name="min-children-per-line">6</property>
-                    <property name="max-children-per-line">6</property>
                     <property name="activate-on-single-click">1</property>
                     <signal name="child-activated" handler="emoji_activated"/>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="objects_heading">
+                  <object class="GtkLabel" id="objects.heading">
                     <property name="label" translatable="yes">Objects</property>
                     <property name="xalign">0</property>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkFlowBox" id="objects_box">
+                  <object class="GtkFlowBox" id="objects.box">
                     <property name="homogeneous">1</property>
                     <property name="selection-mode">none</property>
-                    <property name="row-spacing">6</property>
-                    <property name="column-spacing">6</property>
-                    <property name="min-children-per-line">6</property>
-                    <property name="max-children-per-line">6</property>
                     <property name="activate-on-single-click">1</property>
                     <signal name="child-activated" handler="emoji_activated"/>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="symbols_heading">
+                  <object class="GtkLabel" id="symbols.heading">
                     <property name="label" translatable="yes">Symbols</property>
                     <property name="xalign">0</property>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkFlowBox" id="symbols_box">
+                  <object class="GtkFlowBox" id="symbols.box">
                     <property name="homogeneous">1</property>
                     <property name="selection-mode">none</property>
-                    <property name="row-spacing">6</property>
-                    <property name="column-spacing">6</property>
-                    <property name="min-children-per-line">6</property>
-                    <property name="max-children-per-line">6</property>
                     <property name="activate-on-single-click">1</property>
                     <signal name="child-activated" handler="emoji_activated"/>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="flags_heading">
+                  <object class="GtkLabel" id="flags.heading">
                     <property name="label" translatable="yes">Flags</property>
                     <property name="xalign">0</property>
                   </object>
                 </child>
                 <child>
-                  <object class="GtkFlowBox" id="flags_box">
+                  <object class="GtkFlowBox" id="flags.box">
                     <property name="homogeneous">1</property>
                     <property name="selection-mode">none</property>
-                    <property name="row-spacing">6</property>
-                    <property name="column-spacing">6</property>
-                    <property name="min-children-per-line">6</property>
-                    <property name="max-children-per-line">6</property>
                     <property name="activate-on-single-click">1</property>
                     <signal name="child-activated" handler="emoji_activated"/>
                   </object>
@@ -190,120 +169,83 @@
           <object class="GtkBox">
             <property name="orientation">horizontal</property>
             <child>
-              <object class="GtkButton" id="people_button">
+              <object class="GtkButton" id="recent.button">
                 <property name="relief">none</property>
-                <signal name="clicked" handler="scroll_to_section"/>
                 <style>
                   <class name="emoji-section"/>
                 </style>
-                <child>
-                  <object class="GtkLabel" id="people_label">
-                  </object>
-                </child>
               </object>
             </child>
             <child>
-              <object class="GtkButton" id="body_button">
+              <object class="GtkButton" id="people.button">
                 <property name="relief">none</property>
-                <signal name="clicked" handler="scroll_to_section"/>
                 <style>
                   <class name="emoji-section"/>
                 </style>
-                <child>
-                  <object class="GtkLabel" id="body_label">
-                  </object>
-                </child>
               </object>
             </child>
             <child>
-              <object class="GtkButton" id="nature_button">
+              <object class="GtkButton" id="body.button">
                 <property name="relief">none</property>
-                <signal name="clicked" handler="scroll_to_section"/>
                 <style>
                   <class name="emoji-section"/>
                 </style>
-                <child>
-                  <object class="GtkLabel" id="nature_label">
-                  </object>
-                </child>
               </object>
             </child>
             <child>
-              <object class="GtkButton" id="food_button">
+              <object class="GtkButton" id="nature.button">
                 <property name="relief">none</property>
-                <signal name="clicked" handler="scroll_to_section"/>
                 <style>
                   <class name="emoji-section"/>
                 </style>
-                <child>
-                  <object class="GtkLabel" id="food_label">
-                  </object>
-                </child>
               </object>
             </child>
             <child>
-              <object class="GtkButton" id="travel_button">
+              <object class="GtkButton" id="food.button">
                 <property name="relief">none</property>
-                <signal name="clicked" handler="scroll_to_section"/>
                 <style>
                   <class name="emoji-section"/>
                 </style>
-                <child>
-                  <object class="GtkLabel" id="travel_label">
-                  </object>
-                </child>
               </object>
             </child>
             <child>
-              <object class="GtkButton" id="activities_button">
+              <object class="GtkButton" id="travel.button">
                 <property name="relief">none</property>
-                <signal name="clicked" handler="scroll_to_section"/>
                 <style>
                   <class name="emoji-section"/>
                 </style>
-                <child>
-                  <object class="GtkLabel" id="activities_label">
-                  </object>
-                </child>
               </object>
             </child>
             <child>
-              <object class="GtkButton" id="objects_button">
+              <object class="GtkButton" id="activities.button">
                 <property name="relief">none</property>
-                <signal name="clicked" handler="scroll_to_section"/>
                 <style>
                   <class name="emoji-section"/>
                 </style>
-                <child>
-                  <object class="GtkLabel" id="objects_label">
-                  </object>
-                </child>
               </object>
             </child>
             <child>
-              <object class="GtkButton" id="symbols_button">
+              <object class="GtkButton" id="objects.button">
                 <property name="relief">none</property>
-                <signal name="clicked" handler="scroll_to_section"/>
                 <style>
                   <class name="emoji-section"/>
                 </style>
-                <child>
-                  <object class="GtkLabel" id="symbols_label">
-                  </object>
-                </child>
               </object>
             </child>
             <child>
-              <object class="GtkButton" id="flags_button">
+              <object class="GtkButton" id="symbols.button">
+                <property name="relief">none</property>
+                <style>
+                  <class name="emoji-section"/>
+                </style>
+              </object>
+            </child>
+            <child>
+              <object class="GtkButton" id="flags.button">
                 <property name="relief">none</property>
-                <signal name="clicked" handler="scroll_to_section"/>
                 <style>
                   <class name="emoji-section"/>
                 </style>
-                <child>
-                  <object class="GtkLabel" id="flags_label">
-                  </object>
-                </child>
               </object>
             </child>
           </object>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]