[epiphany] Replace languages list drag & drop green lines with an animation



commit 9cfe2dde682a7feaa430629d2d23f177a265777b
Author: Yetizone <andreii lisita gmail com>
Date:   Mon Aug 17 21:48:21 2020 +0300

    Replace languages list drag & drop green lines with an animation
    
    Also remove unused CSS style classes and regenerate CSS

 src/meson.build                              |   1 +
 src/preferences/ephy-lang-row.c              | 146 +++++++++++++
 src/preferences/ephy-lang-row.h              |  48 ++++
 src/preferences/prefs-general-page.c         | 316 +++++++++++----------------
 src/resources/epiphany.gresource.xml         |   1 +
 src/resources/gtk/lang-row.ui                |  68 ++++++
 src/resources/themes/Adwaita-dark.css        |   8 -
 src/resources/themes/Adwaita.css             |   8 -
 src/resources/themes/HighContrast.css        |   8 -
 src/resources/themes/HighContrastInverse.css |   8 -
 src/resources/themes/_shared-base.scss       |  19 --
 src/resources/themes/elementary.css          |   8 -
 src/resources/themes/shared.css              |   8 -
 13 files changed, 394 insertions(+), 253 deletions(-)
---
diff --git a/src/meson.build b/src/meson.build
index c25d88eff..002cee6db 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -46,6 +46,7 @@ libephymain_sources = [
   'popup-commands.c',
   'preferences/clear-data-view.c',
   'preferences/ephy-data-view.c',
+  'preferences/ephy-lang-row.c',
   'preferences/ephy-prefs-dialog.c',
   'preferences/ephy-search-engine-dialog.c',
   'preferences/passwords-view.c',
diff --git a/src/preferences/ephy-lang-row.c b/src/preferences/ephy-lang-row.c
new file mode 100644
index 000000000..d2899b3fc
--- /dev/null
+++ b/src/preferences/ephy-lang-row.c
@@ -0,0 +1,146 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2020 Andrei Lisita
+ *
+ *  This file is part of Epiphany.
+ *
+ *  Epiphany is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Epiphany is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Epiphany.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ephy-lang-row.h"
+
+enum {
+  DELETE_BUTTON_CLICKED,
+
+  LAST_SIGNAL
+};
+
+struct _EphyLangRow {
+  GtkListBoxRow parent_instance;
+
+  GtkWidget *dnd_top_revealer;
+  GtkWidget *action_row;
+  GtkWidget *drag_event_box;
+  GtkWidget *delete_button;
+  GtkWidget *dnd_bottom_revealer;
+  char *code;
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (EphyLangRow, ephy_lang_row, GTK_TYPE_LIST_BOX_ROW)
+
+static void
+ephy_lang_row_dispose (GObject *object)
+{
+  EphyLangRow *self = EPHY_LANG_ROW (object);
+
+  g_clear_pointer (&self->code, g_free);
+
+  G_OBJECT_CLASS (ephy_lang_row_parent_class)->dispose (object);
+}
+
+static void
+on_delete_button_clicked (GtkWidget   *button,
+                          EphyLangRow *self)
+{
+  g_signal_emit (self, signals[DELETE_BUTTON_CLICKED], 0);
+}
+
+static void
+ephy_lang_row_class_init (EphyLangRowClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  object_class->dispose = ephy_lang_row_dispose;
+
+  gtk_widget_class_set_template_from_resource (widget_class,
+                                               "/org/gnome/epiphany/gtk/lang-row.ui");
+
+  signals[DELETE_BUTTON_CLICKED] =
+    g_signal_new ("delete-button-clicked",
+                  EPHY_TYPE_LANG_ROW,
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL, NULL,
+                  G_TYPE_NONE, 0);
+
+  gtk_widget_class_bind_template_child (widget_class, EphyLangRow, dnd_top_revealer);
+  gtk_widget_class_bind_template_child (widget_class, EphyLangRow, action_row);
+  gtk_widget_class_bind_template_child (widget_class, EphyLangRow, drag_event_box);
+  gtk_widget_class_bind_template_child (widget_class, EphyLangRow, delete_button);
+  gtk_widget_class_bind_template_child (widget_class, EphyLangRow, dnd_bottom_revealer);
+
+  gtk_widget_class_bind_template_callback (widget_class, on_delete_button_clicked);
+}
+
+static void
+ephy_lang_row_init (EphyLangRow *self)
+{
+  gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+GtkWidget *
+ephy_lang_row_new ()
+{
+  return g_object_new (EPHY_TYPE_LANG_ROW, NULL);
+}
+
+void
+ephy_lang_row_set_title (EphyLangRow *self,
+                         const char  *title)
+{
+  hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (self->action_row), title);
+}
+
+void
+ephy_lang_row_set_code (EphyLangRow *self,
+                        const char  *code)
+{
+  if (self->code)
+    g_free (self->code);
+
+  self->code = g_strdup (code);
+}
+
+const char *
+ephy_lang_row_get_code (EphyLangRow *self)
+{
+  return self->code;
+}
+
+GtkWidget *
+ephy_lang_row_get_drag_event_box (EphyLangRow *self)
+{
+  return self->drag_event_box;
+}
+
+void
+ephy_lang_row_set_delete_sensitive (EphyLangRow *self,
+                                    gboolean     sensitive)
+{
+  gtk_widget_set_sensitive (self->delete_button, sensitive);
+}
+
+GtkWidget *
+ephy_lang_row_get_dnd_top_revealer (EphyLangRow *self)
+{
+  return self->dnd_top_revealer;
+}
+
+GtkWidget *
+ephy_lang_row_get_dnd_bottom_revealer (EphyLangRow *self)
+{
+  return self->dnd_bottom_revealer;
+}
diff --git a/src/preferences/ephy-lang-row.h b/src/preferences/ephy-lang-row.h
new file mode 100644
index 000000000..612bc4f32
--- /dev/null
+++ b/src/preferences/ephy-lang-row.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2020 Andrei Lisita
+ *
+ *  This file is part of Epiphany.
+ *
+ *  Epiphany is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Epiphany is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Epiphany.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <handy.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_LANG_ROW (ephy_lang_row_get_type ())
+
+G_DECLARE_FINAL_TYPE (EphyLangRow, ephy_lang_row, EPHY, LANG_ROW, GtkListBoxRow)
+
+GtkWidget      *ephy_lang_row_new                     ();
+
+void            ephy_lang_row_set_title               (EphyLangRow *self,
+                                                       const char  *title);
+
+const char     *ephy_lang_row_get_code                (EphyLangRow *self);
+void            ephy_lang_row_set_code                (EphyLangRow *self,
+                                                       const char  *code);
+
+GtkWidget      *ephy_lang_row_get_drag_event_box      (EphyLangRow *self);
+
+void            ephy_lang_row_set_delete_sensitive    (EphyLangRow *self,
+                                                       gboolean     sensitive);
+
+GtkWidget      *ephy_lang_row_get_dnd_top_revealer    (EphyLangRow *self);
+GtkWidget      *ephy_lang_row_get_dnd_bottom_revealer (EphyLangRow *self);
+
+G_END_DECLS
diff --git a/src/preferences/prefs-general-page.c b/src/preferences/prefs-general-page.c
index 9d6460b14..dda812582 100644
--- a/src/preferences/prefs-general-page.c
+++ b/src/preferences/prefs-general-page.c
@@ -26,6 +26,7 @@
 #include "ephy-file-chooser.h"
 #include "ephy-file-helpers.h"
 #include "ephy-flatpak-utils.h"
+#include "ephy-lang-row.h"
 #include "ephy-langs.h"
 #include "ephy-settings.h"
 #include "ephy-search-engine-dialog.h"
@@ -113,7 +114,7 @@ prefs_general_page_finalize (GObject *object)
 }
 
 static int
-get_list_box_length (GtkWidget *list_box)
+get_list_box_length (GtkListBox *list_box)
 {
   GList *children = gtk_container_get_children (GTK_CONTAINER (list_box));
 
@@ -124,10 +125,11 @@ static void
 language_editor_update_pref (PrefsGeneralPage *general_page)
 {
   GVariantBuilder builder;
-  GtkListBoxRow *row;
-  int index = 0;
+  GtkListBox *lang_listbox = GTK_LIST_BOX (general_page->lang_listbox);
+  int len = get_list_box_length (lang_listbox);
+  int index;
 
-  if (get_list_box_length (general_page->lang_listbox) <= 1) {
+  if (get_list_box_length (lang_listbox) <= 1) {
     g_settings_set (EPHY_SETTINGS_WEB,
                     EPHY_PREFS_WEB_LANGUAGE,
                     "as", NULL);
@@ -136,10 +138,10 @@ language_editor_update_pref (PrefsGeneralPage *general_page)
 
   g_variant_builder_init (&builder, G_VARIANT_TYPE_STRING_ARRAY);
 
-  while ((row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (general_page->lang_listbox), index++))) {
-    char *code;
+  for (index = 0; index < len - 1; index++) {
+    GtkListBoxRow *row = gtk_list_box_get_row_at_index (lang_listbox, index);
+    const char *code = ephy_lang_row_get_code (EPHY_LANG_ROW (row));
 
-    code = g_object_get_data (G_OBJECT (row), "code");
     if (code)
       g_variant_builder_add (&builder, "s", code);
   }
@@ -159,80 +161,48 @@ drag_data_received (GtkWidget        *widget,
                     guint32           time,
                     gpointer          data)
 {
-  GtkWidget *row_before;
-  GtkWidget *row_after;
-  GtkWidget *row;
-  GtkWidget *source;
   PrefsGeneralPage *general_page = data;
-  int len;
-  int pos;
-
-  row_before = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "row-before"));
-  row_after = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "row-after"));
-
-  g_object_set_data (G_OBJECT (widget), "row-before", NULL);
-  g_object_set_data (G_OBJECT (widget), "row-after", NULL);
-
-  if (row_before)
-    gtk_style_context_remove_class (gtk_widget_get_style_context (row_before), "drag-hover-bottom");
-  if (row_after)
-    gtk_style_context_remove_class (gtk_widget_get_style_context (row_after), "drag-hover-top");
-
-  row = (gpointer) * (gpointer *)gtk_selection_data_get_data (selection_data);
-  source = gtk_widget_get_ancestor (row, GTK_TYPE_LIST_BOX_ROW);
-
-  if (source == row_after)
+  GtkListBox *lang_listbox = GTK_LIST_BOX (general_page->lang_listbox);
+  GtkWidget *hovered_row;
+  GtkWidget *dragged_row;
+  int length;
+  int hovered_row_pos;
+  int dragged_row_pos;
+  int insert_pos;
+
+  hovered_row = GTK_WIDGET (gtk_list_box_get_row_at_y (lang_listbox, y));
+  dragged_row = (gpointer) * (gpointer *)gtk_selection_data_get_data (selection_data);
+
+  length = get_list_box_length (GTK_LIST_BOX (widget));
+  hovered_row_pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (hovered_row));
+  dragged_row_pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (dragged_row));
+
+  /* If the drag ended while hovering over the dragged row then we return */
+  if (hovered_row == dragged_row)
     return;
 
-  len = get_list_box_length (general_page->lang_listbox);
-  g_object_ref (source);
-  gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (source)), source);
+  /* If the drag ended while hovering over the "Add Language" row then we return */
+  if (hovered_row_pos == length - 1)
+    return;
 
-  if (row_after)
-    pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (row_after));
-  else
-    pos = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (row_before)) + 1;
+  g_object_ref (dragged_row);
+  gtk_container_remove (GTK_CONTAINER (lang_listbox), dragged_row);
 
-  if (pos + 1 == len)
-    pos--;
+  /* Calculation logic for insert_pos */
+  if (y < 20) {
+    insert_pos = 0;
+  } else if (dragged_row_pos < hovered_row_pos) {
+    insert_pos = hovered_row_pos;
+  } else { /* dragged_row_pos > hovered_row_pos is true here */
+    insert_pos = hovered_row_pos + 1;
+  }
 
-  gtk_list_box_insert (GTK_LIST_BOX (widget), source, pos);
-  g_object_unref (source);
+  gtk_list_box_insert (lang_listbox, dragged_row, insert_pos);
+  g_object_unref (dragged_row);
 
   language_editor_update_pref (general_page);
 }
 
-static GtkListBoxRow *
-get_row_before (GtkListBox    *list,
-                GtkListBoxRow *row)
-{
-  int pos = gtk_list_box_row_get_index (row);
-  return gtk_list_box_get_row_at_index (list, pos - 1);
-}
-
-static GtkListBoxRow *
-get_row_after (GtkListBox    *list,
-               GtkListBoxRow *row)
-{
-  int pos = gtk_list_box_row_get_index (row);
-  return gtk_list_box_get_row_at_index (list, pos + 1);
-}
-
-static GtkListBoxRow *
-get_last_row (GtkListBox *list)
-{
-  int i;
-
-  for (i = 0;; i++) {
-    GtkListBoxRow *tmp;
-    tmp = gtk_list_box_get_row_at_index (list, i);
-    if (tmp == NULL)
-      break;
-  }
-
-  return i > 0 ? gtk_list_box_get_row_at_index (list, i - 1) : NULL;
-}
-
 static gboolean
 drag_motion (GtkWidget      *widget,
              GdkDragContext *context,
@@ -240,77 +210,57 @@ drag_motion (GtkWidget      *widget,
              int             y,
              guint           time)
 {
-  GtkAllocation alloc;
-  GtkWidget *row;
-  int hover_row_y;
-  int hover_row_height;
-  GtkWidget *drag_row;
-  GtkWidget *row_before;
-  GtkWidget *row_after;
-
-  row = GTK_WIDGET (gtk_list_box_get_row_at_y (GTK_LIST_BOX (widget), y));
-
-  drag_row = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "drag-row"));
-  row_before = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "row-before"));
-  row_after = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "row-after"));
-
-  gtk_style_context_remove_class (gtk_widget_get_style_context (drag_row), "drag-hover");
-  if (row_before)
-    gtk_style_context_remove_class (gtk_widget_get_style_context (row_before), "drag-hover-bottom");
-  if (row_after)
-    gtk_style_context_remove_class (gtk_widget_get_style_context (row_after), "drag-hover-top");
-
-  if (row) {
-    gtk_widget_get_allocation (row, &alloc);
-    hover_row_y = alloc.y;
-    hover_row_height = alloc.height;
-
-    if (y < hover_row_y + hover_row_height / 2) {
-      row_after = row;
-      row_before = GTK_WIDGET (get_row_before (GTK_LIST_BOX (widget), GTK_LIST_BOX_ROW (row)));
-    } else {
-      row_before = row;
-      row_after = GTK_WIDGET (get_row_after (GTK_LIST_BOX (widget), GTK_LIST_BOX_ROW (row)));
-    }
-  } else {
-    row_before = GTK_WIDGET (get_last_row (GTK_LIST_BOX (widget)));
-    row_after = NULL;
+  GtkListBoxRow *first_lang_row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (widget), 0);
+
+  GtkWidget *dragged_row;
+  GtkWidget *hovered_row;
+  GtkWidget *expanded_dnd_revealer;
+  GtkWidget *hovered_row_dnd_revealer = NULL;
+
+  dragged_row = g_object_get_data (G_OBJECT (widget), "dragged-row");
+  hovered_row = GTK_WIDGET (gtk_list_box_get_row_at_y (GTK_LIST_BOX (widget), y));
+  expanded_dnd_revealer = g_object_get_data (G_OBJECT (widget), "dnd-expanded-revealer");
+
+  if (EPHY_IS_LANG_ROW (hovered_row))
+    hovered_row_dnd_revealer = ephy_lang_row_get_dnd_bottom_revealer (EPHY_LANG_ROW (hovered_row));
+
+  /* Edge case: If the user is hovering with the dragged row close to the
+   * top of the list, then we reveal the top empty row of EphyLangRow */
+  if (y < 20 && dragged_row != GTK_WIDGET (first_lang_row)) {
+    GtkWidget *top_revealer = ephy_lang_row_get_dnd_top_revealer (EPHY_LANG_ROW (hovered_row));
+
+    if (expanded_dnd_revealer)
+      gtk_revealer_set_reveal_child (GTK_REVEALER (expanded_dnd_revealer), FALSE);
+
+    gtk_revealer_set_reveal_child (GTK_REVEALER (top_revealer), TRUE);
+    g_object_set_data (G_OBJECT (widget), "dnd-expanded-revealer", top_revealer);
+
+    return TRUE;
   }
 
-  g_object_set_data (G_OBJECT (widget), "row-before", row_before);
-  g_object_set_data (G_OBJECT (widget), "row-after", row_after);
+  if (dragged_row == hovered_row) {
+    if (expanded_dnd_revealer)
+      gtk_revealer_set_reveal_child (GTK_REVEALER (expanded_dnd_revealer), FALSE);
 
-  if (drag_row == row_before || drag_row == row_after) {
-    gtk_style_context_add_class (gtk_widget_get_style_context (drag_row), "drag-hover");
-    return FALSE;
+    g_object_set_data (G_OBJECT (widget), "dnd-expanded-revealer", NULL);
+
+    return TRUE;
   }
 
-  if (row_before)
-    gtk_style_context_add_class (gtk_widget_get_style_context (row_before), "drag-hover-bottom");
-  if (row_after)
-    gtk_style_context_add_class (gtk_widget_get_style_context (row_after), "drag-hover-top");
+  if (EPHY_IS_LANG_ROW (hovered_row)) {
+    if (expanded_dnd_revealer)
+      gtk_revealer_set_reveal_child (GTK_REVEALER (expanded_dnd_revealer), FALSE);
 
-  return TRUE;
-}
+    gtk_revealer_set_reveal_child (GTK_REVEALER (hovered_row_dnd_revealer), TRUE);
+    g_object_set_data (G_OBJECT (widget), "dnd-expanded-revealer", hovered_row_dnd_revealer);
+    return TRUE;
+  } else {
+    if (expanded_dnd_revealer)
+      gtk_revealer_set_reveal_child (GTK_REVEALER (expanded_dnd_revealer), FALSE);
 
-static void
-drag_leave (GtkWidget      *widget,
-            GdkDragContext *context,
-            guint           time)
-{
-  GtkWidget *drag_row;
-  GtkWidget *row_before;
-  GtkWidget *row_after;
-
-  drag_row = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "drag-row"));
-  row_before = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "row-before"));
-  row_after = GTK_WIDGET (g_object_get_data (G_OBJECT (widget), "row-after"));
-
-  gtk_style_context_remove_class (gtk_widget_get_style_context (drag_row), "drag-hover");
-  if (row_before)
-    gtk_style_context_remove_class (gtk_widget_get_style_context (row_before), "drag-hover-bottom");
-  if (row_after)
-    gtk_style_context_remove_class (gtk_widget_get_style_context (row_after), "drag-hover-top");
+    g_object_set_data (G_OBJECT (widget), "dnd-expanded-revealer", NULL);
+    return FALSE;
+  }
 }
 
 static GtkDialog *setup_add_language_dialog (PrefsGeneralPage *general_page);
@@ -357,36 +307,33 @@ language_editor_add_function_buttons (PrefsGeneralPage *general_page)
 static void
 language_editor_update_state (PrefsGeneralPage *general_page)
 {
-  int length = get_list_box_length (general_page->lang_listbox);
+  GtkListBox *lang_listbox = GTK_LIST_BOX (general_page->lang_listbox);
+  int length = get_list_box_length (lang_listbox);
   int index;
 
+  /* If there's only one language row in the list we want to make its
+   * remove button insensitive */
   if (length == 2) {
-    GtkListBoxRow *row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (general_page->lang_listbox), 0);
-    GtkWidget *action = g_object_get_data (G_OBJECT (row), "action");
+    GtkListBoxRow *row = gtk_list_box_get_row_at_index (lang_listbox, 0);
 
-    gtk_widget_set_sensitive (action, FALSE);
+    ephy_lang_row_set_delete_sensitive (EPHY_LANG_ROW (row), FALSE);
     return;
   }
 
   for (index = 0; index < length - 1; index++) {
-    GtkListBoxRow *row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (general_page->lang_listbox), index);
-    GtkWidget *action = g_object_get_data (G_OBJECT (row), "action");
+    GtkListBoxRow *row = gtk_list_box_get_row_at_index (lang_listbox, index);
 
-    gtk_widget_set_sensitive (action, TRUE);
+    ephy_lang_row_set_delete_sensitive (EPHY_LANG_ROW (row), TRUE);
   }
 }
 
 static void
-language_editor_remove_button_clicked_cb (GtkWidget        *button,
+language_editor_delete_button_clicked_cb (EphyLangRow      *row,
                                           PrefsGeneralPage *general_page)
 {
-  GtkWidget *row = g_object_get_data (G_OBJECT (button), "row");
-
-  if (row) {
-    gtk_container_remove (GTK_CONTAINER (general_page->lang_listbox), row);
-    language_editor_update_pref (general_page);
-    language_editor_update_state (general_page);
-  }
+  gtk_container_remove (GTK_CONTAINER (general_page->lang_listbox), GTK_WIDGET (row));
+  language_editor_update_pref (general_page);
+  language_editor_update_state (general_page);
 }
 
 void
@@ -397,10 +344,12 @@ drag_data_get (GtkWidget        *widget,
                guint             time,
                gpointer          data)
 {
+  GtkWidget *row = gtk_widget_get_ancestor (widget, EPHY_TYPE_LANG_ROW);
+
   gtk_selection_data_set (selection_data,
-                          gdk_atom_intern_static_string ("GTK_LIST_BOX_ROW"),
+                          gdk_atom_intern_static_string ("EPHY_LANG_ROW"),
                           32,
-                          (const guchar *)&widget,
+                          (const guchar *)&row,
                           sizeof (gpointer));
 }
 
@@ -416,7 +365,7 @@ drag_begin (GtkWidget      *widget,
   int x, y;
   double sx, sy;
 
-  row = gtk_widget_get_ancestor (widget, GTK_TYPE_LIST_BOX_ROW);
+  row = gtk_widget_get_ancestor (widget, EPHY_TYPE_LANG_ROW);
   gtk_widget_get_allocation (row, &alloc);
   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, alloc.width, alloc.height);
   cr = cairo_create (surface);
@@ -433,7 +382,7 @@ drag_begin (GtkWidget      *widget,
   cairo_destroy (cr);
   cairo_surface_destroy (surface);
 
-  g_object_set_data (G_OBJECT (gtk_widget_get_parent (row)), "drag-row", row);
+  g_object_set_data (G_OBJECT (gtk_widget_get_parent (row)), "dragged-row", row);
   gtk_style_context_add_class (gtk_widget_get_style_context (row), "drag-row");
 }
 
@@ -442,12 +391,21 @@ drag_end (GtkWidget      *widget,
           GdkDragContext *context,
           gpointer        data)
 {
-  GtkWidget *row;
+  GtkWidget *lang_row;
+  GtkWidget *lang_listbox;
+  GtkWidget *dnd_expanded_revealer;
 
-  row = gtk_widget_get_ancestor (widget, GTK_TYPE_LIST_BOX_ROW);
-  g_object_set_data (G_OBJECT (gtk_widget_get_parent (row)), "drag-row", NULL);
-  gtk_style_context_remove_class (gtk_widget_get_style_context (row), "drag-row");
-  gtk_style_context_remove_class (gtk_widget_get_style_context (row), "drag-hover");
+  lang_row = gtk_widget_get_ancestor (widget, EPHY_TYPE_LANG_ROW);
+  lang_listbox = gtk_widget_get_parent (lang_row);
+  dnd_expanded_revealer = g_object_get_data (G_OBJECT (lang_listbox), "dnd-expanded-revealer");
+
+  g_object_set_data (G_OBJECT (lang_listbox), "dragged-row", NULL);
+  gtk_style_context_remove_class (gtk_widget_get_style_context (lang_row), "drag-row");
+
+  if (dnd_expanded_revealer) {
+    gtk_revealer_set_reveal_child (GTK_REVEALER (dnd_expanded_revealer), FALSE);
+    g_object_set_data (G_OBJECT (lang_listbox), "dnd-expanded-revealer", NULL);
+  }
 }
 
 static GtkTargetEntry entries[] = {
@@ -459,53 +417,40 @@ language_editor_add (PrefsGeneralPage *general_page,
                      const char       *code,
                      const char       *desc)
 {
-  GtkWidget *event_box;
   GtkWidget *row;
-  GtkWidget *prefix;
-  GtkWidget *action;
+  GtkWidget *event_box;
   int len;
   int index;
 
   g_assert (code != NULL && desc != NULL);
 
-  len = get_list_box_length (general_page->lang_listbox);
+  len = get_list_box_length (GTK_LIST_BOX (general_page->lang_listbox));
 
-  for (index = 0; index < len; index++) {
+  for (index = 0; index < len - 1; index++) {
     GtkListBoxRow *widget;
-    char *row_code;
+    const char *row_code;
 
     widget = gtk_list_box_get_row_at_index (GTK_LIST_BOX (general_page->lang_listbox), index);
 
-    row_code = g_object_get_data (G_OBJECT (widget), "code");
+    row_code = ephy_lang_row_get_code (EPHY_LANG_ROW (widget));
     if (row_code && strcmp (row_code, code) == 0)
       return;
   }
 
-  row = hdy_action_row_new ();
-  hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (row), desc);
-  g_object_set_data (G_OBJECT (row), "code", g_strdup (code));
-  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (row)), "draggable");
+  row = ephy_lang_row_new ();
+
+  ephy_lang_row_set_title (EPHY_LANG_ROW (row), desc);
+  gtk_style_context_add_class (gtk_widget_get_style_context (row), "row");
 
-  event_box = gtk_event_box_new ();
-  gtk_drag_source_set (GTK_WIDGET (event_box), GDK_BUTTON1_MASK, entries, 1, GDK_ACTION_MOVE);
+  event_box = ephy_lang_row_get_drag_event_box (EPHY_LANG_ROW (row));
+  gtk_drag_source_set (event_box, GDK_BUTTON1_MASK, entries, 1, GDK_ACTION_MOVE);
   g_signal_connect (event_box, "drag-begin", G_CALLBACK (drag_begin), general_page);
   g_signal_connect (event_box, "drag-end", G_CALLBACK (drag_end), general_page);
   g_signal_connect (event_box, "drag-data-get", G_CALLBACK (drag_data_get), general_page);
-  prefix = gtk_image_new_from_icon_name ("list-drag-handle-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
-  gtk_container_add (GTK_CONTAINER (event_box), prefix);
-  hdy_action_row_add_prefix (HDY_ACTION_ROW (row), event_box);
-
-  action = gtk_button_new_from_icon_name ("edit-delete-symbolic", GTK_ICON_SIZE_SMALL_TOOLBAR);
-  gtk_widget_set_tooltip_text (action, _("Delete language"));
-  g_object_set_data (G_OBJECT (row), "action", action);
-  g_object_set_data (G_OBJECT (action), "row", row);
-  g_signal_connect (action, "clicked", G_CALLBACK (language_editor_remove_button_clicked_cb), general_page);
-  gtk_widget_set_valign (action, GTK_ALIGN_CENTER);
-  gtk_container_add (GTK_CONTAINER (row), action);
 
-  gtk_widget_show_all (GTK_WIDGET (row));
+  g_signal_connect (row, "delete-button-clicked", G_CALLBACK (language_editor_delete_button_clicked_cb), 
general_page);
 
-  gtk_list_box_insert (GTK_LIST_BOX (general_page->lang_listbox), GTK_WIDGET (row), len - 1);
+  gtk_list_box_insert (GTK_LIST_BOX (general_page->lang_listbox), row, len - 1);
 }
 
 static void
@@ -1178,7 +1123,6 @@ init_lang_listbox (PrefsGeneralPage *general_page)
   gtk_drag_dest_set (general_page->lang_listbox, GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, entries, 
1, GDK_ACTION_MOVE);
   g_signal_connect (general_page->lang_listbox, "drag-data-received", G_CALLBACK (drag_data_received), 
general_page);
   g_signal_connect (general_page->lang_listbox, "drag-motion", G_CALLBACK (drag_motion), NULL);
-  g_signal_connect (general_page->lang_listbox, "drag-leave", G_CALLBACK (drag_leave), NULL);
 
   list = g_settings_get_strv (EPHY_SETTINGS_WEB,
                               EPHY_PREFS_WEB_LANGUAGE);
diff --git a/src/resources/epiphany.gresource.xml b/src/resources/epiphany.gresource.xml
index eba57f3c5..861486aec 100644
--- a/src/resources/epiphany.gresource.xml
+++ b/src/resources/epiphany.gresource.xml
@@ -23,6 +23,7 @@
     <file preprocess="xml-stripblanks" compressed="true">gtk/encoding-dialog.ui</file>
     <file preprocess="xml-stripblanks" compressed="true">gtk/encoding-row.ui</file>
     <file preprocess="xml-stripblanks" compressed="true">gtk/history-dialog.ui</file>
+    <file preprocess="xml-stripblanks" compressed="true">gtk/lang-row.ui</file>
     <file preprocess="xml-stripblanks" compressed="true">gtk/notebook-context-menu.ui</file>
     <file preprocess="xml-stripblanks" compressed="true">gtk/page-menu-popover.ui</file>
     <file preprocess="xml-stripblanks" compressed="true">gtk/page-row.ui</file>
diff --git a/src/resources/gtk/lang-row.ui b/src/resources/gtk/lang-row.ui
new file mode 100644
index 000000000..8eb3307d9
--- /dev/null
+++ b/src/resources/gtk/lang-row.ui
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <template class="EphyLangRow" parent="GtkListBoxRow">
+    <property name="visible">True</property>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
+        <child>
+          <object class="GtkRevealer" id="dnd_top_revealer">
+            <property name="visible">True</property>
+            <child>
+              <object class="HdyActionRow">
+                <property name="visible">True</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="HdyActionRow" id="action_row">
+            <property name="visible">True</property>
+            <child type="prefix">
+              <object class="GtkEventBox" id="drag_event_box">
+                <property name="visible">True</property>
+                <child>
+                  <object class="GtkImage">
+                    <property name="visible">True</property>
+                    <property name="icon-name">list-drag-handle-symbolic</property>
+                    <property name="icon-size">1</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkButton" id="delete_button">
+                <property name="visible">True</property>
+                <property name="valign">GTK_ALIGN_CENTER</property>
+                <property name="tooltip-text" translatable="yes">Delete language</property>
+                <signal name="clicked" handler="on_delete_button_clicked"/>
+                <child>
+                  <object class="GtkImage">
+                    <property name="visible">True</property>
+                    <property name="icon-name">edit-delete-symbolic</property>
+                    <property name="icon-size">2</property>
+                    <style>
+                      <class name="image-button"/>
+                    </style>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkRevealer" id="dnd_bottom_revealer">
+            <property name="visible">True</property>
+            <child>
+              <object class="HdyActionRow">
+                <property name="visible">True</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/resources/themes/Adwaita-dark.css b/src/resources/themes/Adwaita-dark.css
index 80e2adf7a..5e0997c65 100644
--- a/src/resources/themes/Adwaita-dark.css
+++ b/src/resources/themes/Adwaita-dark.css
@@ -82,14 +82,6 @@ dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > li
 
 .draggable.drag-row { color: gray; background: alpha(gray,0.2); }
 
-.draggable.drag-row.drag-hover { border-top: 1px solid #4e9a06; border-bottom: 1px solid #4e9a06; }
-
-.draggable.drag-hover image, .draggable.drag-hover label { color: #4e9a06; }
-
-.draggable.drag-hover-top { border-top: 1px solid #4e9a06; }
-
-.draggable.drag-hover-bottom { border-bottom: 1px solid #4e9a06; }
-
 .incognito-mode { /*************************** Check and Radio buttons * */ }
 
 .incognito-mode headerbar { background: #141927 linear-gradient(to top, #1a2235, #1e263b); box-shadow: inset 
0 1px rgba(231, 234, 243, 0.07); border-color: #06080c; }
diff --git a/src/resources/themes/Adwaita.css b/src/resources/themes/Adwaita.css
index b29415315..a6438de31 100644
--- a/src/resources/themes/Adwaita.css
+++ b/src/resources/themes/Adwaita.css
@@ -82,14 +82,6 @@ dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > li
 
 .draggable.drag-row { color: gray; background: alpha(gray,0.2); }
 
-.draggable.drag-row.drag-hover { border-top: 1px solid #4e9a06; border-bottom: 1px solid #4e9a06; }
-
-.draggable.drag-hover image, .draggable.drag-hover label { color: #4e9a06; }
-
-.draggable.drag-hover-top { border-top: 1px solid #4e9a06; }
-
-.draggable.drag-hover-bottom { border-bottom: 1px solid #4e9a06; }
-
 .incognito-mode { /*************************** Check and Radio buttons * */ }
 
 .incognito-mode headerbar { background: #c4d6e9 linear-gradient(to top, #bdd1e6, #c8d9ea); box-shadow: inset 
0 1px rgba(255, 255, 255, 0.8); border-color: #91b2d6; }
diff --git a/src/resources/themes/HighContrast.css b/src/resources/themes/HighContrast.css
index 87d952a93..b9a1d0cd3 100644
--- a/src/resources/themes/HighContrast.css
+++ b/src/resources/themes/HighContrast.css
@@ -82,14 +82,6 @@ dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > li
 
 .draggable.drag-row { color: gray; background: alpha(gray,0.2); }
 
-.draggable.drag-row.drag-hover { border-top: 1px solid #4e9a06; border-bottom: 1px solid #4e9a06; }
-
-.draggable.drag-hover image, .draggable.drag-hover label { color: #4e9a06; }
-
-.draggable.drag-hover-top { border-top: 1px solid #4e9a06; }
-
-.draggable.drag-hover-bottom { border-bottom: 1px solid #4e9a06; }
-
 .incognito-mode { /*************************** Check and Radio buttons * */ }
 
 .incognito-mode headerbar { background: #d0deed linear-gradient(to top, #c8d9ea, #d3e0ef); box-shadow: inset 
0 1px rgba(255, 255, 255, 0.8); border-color: #345d8a; }
diff --git a/src/resources/themes/HighContrastInverse.css b/src/resources/themes/HighContrastInverse.css
index 32f872de9..2944dc90f 100644
--- a/src/resources/themes/HighContrastInverse.css
+++ b/src/resources/themes/HighContrastInverse.css
@@ -82,14 +82,6 @@ dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > li
 
 .draggable.drag-row { color: gray; background: alpha(gray,0.2); }
 
-.draggable.drag-row.drag-hover { border-top: 1px solid #4e9a06; border-bottom: 1px solid #4e9a06; }
-
-.draggable.drag-hover image, .draggable.drag-hover label { color: #4e9a06; }
-
-.draggable.drag-hover-top { border-top: 1px solid #4e9a06; }
-
-.draggable.drag-hover-bottom { border-bottom: 1px solid #4e9a06; }
-
 .incognito-mode { /*************************** Check and Radio buttons * */ }
 
 .incognito-mode headerbar { background: #101520 linear-gradient(to top, #171d2e, #1a2235); box-shadow: inset 
0 1px rgba(231, 234, 243, 0.07); border-color: #36456b; }
diff --git a/src/resources/themes/_shared-base.scss b/src/resources/themes/_shared-base.scss
index 7e5d60ca8..731d8356f 100644
--- a/src/resources/themes/_shared-base.scss
+++ b/src/resources/themes/_shared-base.scss
@@ -232,24 +232,5 @@ dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > li
   &.drag-row {
     color: gray;
     background: gtkalpha(gray, 0.2);
-
-    &.drag-hover {
-      border-top: 1px solid #4e9a06;
-      border-bottom: 1px solid #4e9a06;
-    }
-  }
-
-  &.drag-hover {
-    image, label {
-      color: #4e9a06;
-    }
-  }
-
-  &.drag-hover-top {
-    border-top: 1px solid #4e9a06;
-  }
-
-  &.drag-hover-bottom {
-    border-bottom: 1px solid #4e9a06;
   }
 }
diff --git a/src/resources/themes/elementary.css b/src/resources/themes/elementary.css
index e0f00de66..a43cbffa8 100644
--- a/src/resources/themes/elementary.css
+++ b/src/resources/themes/elementary.css
@@ -82,14 +82,6 @@ dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > li
 
 .draggable.drag-row { color: gray; background: alpha(gray,0.2); }
 
-.draggable.drag-row.drag-hover { border-top: 1px solid #4e9a06; border-bottom: 1px solid #4e9a06; }
-
-.draggable.drag-hover image, .draggable.drag-hover label { color: #4e9a06; }
-
-.draggable.drag-hover-top { border-top: 1px solid #4e9a06; }
-
-.draggable.drag-hover-bottom { border-bottom: 1px solid #4e9a06; }
-
 .page-menu-contents { margin-left: 0px; margin-right: 0px; margin-bottom: 6px; }
 
 .page-menu-zoom-box { margin-bottom: 6px; }
diff --git a/src/resources/themes/shared.css b/src/resources/themes/shared.css
index 80527d428..e0deee568 100644
--- a/src/resources/themes/shared.css
+++ b/src/resources/themes/shared.css
@@ -81,11 +81,3 @@ dzlsuggestionpopover > revealer > box > elastic > scrolledwindow > viewport > li
 .draggable.drag-icon { background: white; border: 1px solid black; }
 
 .draggable.drag-row { color: gray; background: alpha(gray,0.2); }
-
-.draggable.drag-row.drag-hover { border-top: 1px solid #4e9a06; border-bottom: 1px solid #4e9a06; }
-
-.draggable.drag-hover image, .draggable.drag-hover label { color: #4e9a06; }
-
-.draggable.drag-hover-top { border-top: 1px solid #4e9a06; }
-
-.draggable.drag-hover-bottom { border-bottom: 1px solid #4e9a06; }


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