[gnome-control-center/wip/feborges/new-users-panel: 5/8] user-accounts: Draw arrow in UmCarousel



commit 27f9feda3698a05a68f0172b982dfed4b049737f
Author: Felipe Borges <felipeborges gnome org>
Date:   Sun Dec 18 13:57:03 2016 +0100

    user-accounts: Draw arrow in UmCarousel
    
    The arrow is drawn using CSS.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=767065

 panels/user-accounts/data/carousel.css           |   20 ++++
 panels/user-accounts/data/carousel.ui            |  100 ++++++++++++++------
 panels/user-accounts/um-carousel.c               |  105 +++++++++++++++++++---
 panels/user-accounts/user-accounts.gresource.xml |    1 +
 4 files changed, 182 insertions(+), 44 deletions(-)
---
diff --git a/panels/user-accounts/data/carousel.css b/panels/user-accounts/data/carousel.css
new file mode 100644
index 0000000..ac74c8c
--- /dev/null
+++ b/panels/user-accounts/data/carousel.css
@@ -0,0 +1,20 @@
+.carousel-arrow-container {
+  border-bottom: 1px solid @borders;
+}
+
+.carousel-arrow,
+.carousel-inner-arrow {
+  border-width: 20px; /* ARROW_SIZE */
+  border-style: solid;
+  border-color: transparent;
+}
+
+.carousel-arrow {
+  border-bottom-color: @borders;
+  margin-bottom: -1px;
+}
+
+.carousel-inner-arrow {
+  border-bottom-color: @theme_bg_color;
+  margin-bottom: -2px;
+}
diff --git a/panels/user-accounts/data/carousel.ui b/panels/user-accounts/data/carousel.ui
index ecf6cf0..667484a 100644
--- a/panels/user-accounts/data/carousel.ui
+++ b/panels/user-accounts/data/carousel.ui
@@ -20,51 +20,91 @@
           </object>
         </child>
         <child type="overlay">
-          <object class="GtkBox">
+          <object class="GtkOverlay">
             <property name="visible">True</property>
-            <property name="orientation">horizontal</property>
-            <property name="border_width">12</property>
             <child>
-              <object class="GtkButton" id="go_back_button">
-                <property name="visible">False</property>
-                <property name="can_focus">True</property>
-                <property name="valign">center</property>
-                <style>
-                  <class name="circular"/>
-                </style>
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+                <property name="border_width">12</property>
                 <child>
-                  <object class="GtkImage">
-                    <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="icon-size">4</property>
-                    <property name="icon_name">go-previous-symbolic</property>
+                  <object class="GtkButton" id="go_back_button">
+                    <property name="visible">False</property>
+                    <property name="can_focus">True</property>
+                    <property name="valign">center</property>
+                    <style>
+                      <class name="circular"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="icon-size">4</property>
+                        <property name="icon_name">go-previous-symbolic</property>
+                      </object>
+                    </child>
+                    <signal name="clicked" handler="um_carousel_goto_previous_page" object="UmCarousel" 
swapped="no"/>
                   </object>
+                  <packing>
+                    <property name="pack_type">GTK_PACK_START</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="go_next_button">
+                    <property name="can_focus">True</property>
+                    <property name="valign">center</property>
+                    <style>
+                      <class name="circular"/>
+                    </style>
+                    <child>
+                      <object class="GtkImage">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="icon-size">4</property>
+                        <property name="icon_name">go-next-symbolic</property>
+                      </object>
+                    </child>
+                    <signal name="clicked" handler="um_carousel_goto_next_page" object="UmCarousel" 
swapped="no"/>
+                  </object>
+                  <packing>
+                    <property name="pack_type">GTK_PACK_END</property>
+                  </packing>
                 </child>
-                <signal name="clicked" handler="um_carousel_goto_previous_page" object="UmCarousel" 
swapped="no"/>
               </object>
-              <packing>
-                <property name="pack_type">start</property>
-              </packing>
             </child>
-            <child>
-              <object class="GtkButton" id="go_next_button">
-                <property name="can_focus">True</property>
-                <property name="valign">center</property>
+            <child type="overlay">
+              <object class="GtkBox">
+                <property name="visible">True</property>
+                <property name="valign">GTK_ALIGN_END</property>
                 <style>
-                  <class name="circular"/>
+                  <class name="carousel-arrow-container"/>
                 </style>
                 <child>
-                  <object class="GtkImage">
+                  <object class="GtkOverlay">
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="icon-size">4</property>
-                    <property name="icon_name">go-next-symbolic</property>
+                    <child>
+                      <object class="GtkBox" id="arrow">
+                        <property name="visible">True</property>
+                        <property name="halign">GTK_ALIGN_END</property>
+                        <style>
+                          <class name="carousel-arrow"/>
+                        </style>
+                      </object>
+                    </child>
+                    <child type="overlay">
+                      <object class="GtkBox">
+                        <property name="visible">True</property>
+                        <property name="halign">GTK_ALIGN_END</property>
+                        <style>
+                          <class name="carousel-inner-arrow"/>
+                        </style>
+                      </object>
+                    </child>
                   </object>
                 </child>
-                <signal name="clicked" handler="um_carousel_goto_next_page" object="UmCarousel" 
swapped="no"/>
               </object>
               <packing>
-                <property name="pack_type">end</property>
+                <property name="pass-through">True</property>
               </packing>
             </child>
           </object>
diff --git a/panels/user-accounts/um-carousel.c b/panels/user-accounts/um-carousel.c
index d2ba85d..c07dc39 100644
--- a/panels/user-accounts/um-carousel.c
+++ b/panels/user-accounts/um-carousel.c
@@ -23,6 +23,8 @@
 #include <glib-object.h>
 #include <gtk/gtk.h>
 
+#define ARROW_SIZE 20
+
 struct _UmCarouselItem {
         GtkToggleButton parent;
 
@@ -54,11 +56,14 @@ struct _UmCarousel {
         gint visible_page;
         UmCarouselItem *selected_item;
         GtkWidget *last_box;
+        GtkWidget *arrow;
 
         /* Widgets */
         GtkStack *stack;
         GtkWidget *go_back_button;
         GtkWidget *go_next_button;
+
+        GtkStyleProvider *provider;
 };
 
 G_DEFINE_TYPE (UmCarousel, um_carousel, GTK_TYPE_REVEALER)
@@ -73,6 +78,58 @@ static guint signals[NUM_SIGNALS] = { 0, };
 #define ITEMS_PER_PAGE 3
 
 static gint
+um_carousel_item_get_x (UmCarouselItem *item,
+                        UmCarousel     *carousel)
+{
+        GtkWidget *widget, *parent;
+        gint width;
+        gint dest_x;
+
+        parent = GTK_WIDGET (carousel->stack);
+        widget = GTK_WIDGET (item);
+
+        width = gtk_widget_get_allocated_width (widget);
+        gtk_widget_translate_coordinates (widget,
+                                          parent,
+                                          width / 2,
+                                          0,
+                                          &dest_x,
+                                          NULL);
+
+        return CLAMP (dest_x - ARROW_SIZE,
+                      0,
+                      gtk_widget_get_allocated_width (parent));
+}
+
+static void
+um_carousel_move_arrow (UmCarousel *self)
+{
+        GtkStyleContext *context;
+        gchar *css;
+        gint end_x;
+
+        if (!self->selected_item)
+                return;
+
+        end_x = um_carousel_item_get_x (self->selected_item, self);
+
+        context = gtk_widget_get_style_context (self->arrow);
+        if (self->provider)
+                gtk_style_context_remove_provider (context, self->provider);
+        g_clear_object (&self->provider);
+
+        css = g_strdup_printf ("* {\n"
+                               "  margin-left: %dpx;\n"
+                               "}\n", end_x);
+
+        self->provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
+        gtk_css_provider_load_from_data (GTK_CSS_PROVIDER (self->provider), css, -1, NULL);
+        gtk_style_context_add_provider (context, self->provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+        g_free (css);
+}
+
+static gint
 get_last_page_number (UmCarousel *self)
 {
         if (g_list_length (self->children) == 0)
@@ -120,15 +177,26 @@ um_carousel_find_item (UmCarousel    *self,
         return NULL;
 }
 
+static void
+on_item_toggled (UmCarouselItem *item,
+                 gpointer        user_data)
+{
+        UmCarousel *self = UM_CAROUSEL (user_data);
+
+        self->selected_item = item;
+
+        g_signal_emit (user_data, signals[ITEM_ACTIVATED], 0, item);
+
+        um_carousel_move_arrow (self);
+}
+
 void
 um_carousel_select_item (UmCarousel     *self,
                          UmCarouselItem *item)
 {
         gchar *page_name;
 
-        self->selected_item = item;
-
-        g_signal_emit (self, signals[ITEM_ACTIVATED], 0, self->selected_item);
+        on_item_toggled (item, self);
 
         self->visible_page = item->page;
         page_name = g_strdup_printf ("%d", self->visible_page);
@@ -181,17 +249,6 @@ um_carousel_goto_next_page (GtkWidget *button,
 }
 
 static void
-on_item_toggled (UmCarouselItem *item,
-                 gpointer        user_data)
-{
-        UmCarousel *self = UM_CAROUSEL (user_data);
-
-        self->selected_item = item;
-
-        g_signal_emit (user_data, signals[ITEM_ACTIVATED], 0, item);
-}
-
-static void
 um_carousel_add (GtkContainer *container,
                  GtkWidget    *widget)
 {
@@ -224,6 +281,10 @@ um_carousel_add (GtkContainer *container,
         gtk_widget_show_all (self->last_box);
 
         update_buttons_visibility (self);
+
+        /* If there's only one child, select it. */
+        if (self->children->next == NULL)
+                um_carousel_select_item_at_index (self, 0);
 }
 
 void
@@ -236,6 +297,7 @@ um_carousel_purge_items (UmCarousel *self)
         g_list_free (self->children);
         self->children = NULL;
         self->visible_page = 0;
+        self->selected_item = NULL;
 }
 
 UmCarousel *
@@ -256,6 +318,7 @@ um_carousel_class_init (UmCarouselClass *klass)
         gtk_widget_class_bind_template_child (wclass, UmCarousel, stack);
         gtk_widget_class_bind_template_child (wclass, UmCarousel, go_back_button);
         gtk_widget_class_bind_template_child (wclass, UmCarousel, go_next_button);
+        gtk_widget_class_bind_template_child (wclass, UmCarousel, arrow);
 
         gtk_widget_class_bind_template_callback (wclass, um_carousel_goto_previous_page);
         gtk_widget_class_bind_template_callback (wclass, um_carousel_goto_next_page);
@@ -275,5 +338,19 @@ um_carousel_class_init (UmCarouselClass *klass)
 static void
 um_carousel_init (UmCarousel *self)
 {
+        GtkStyleProvider *provider;
+
         gtk_widget_init_template (GTK_WIDGET (self));
+
+        provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
+        gtk_css_provider_load_from_resource (GTK_CSS_PROVIDER (provider),
+                                             "/org/gnome/control-center/user-accounts/carousel.css");
+
+        gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+                                                   provider,
+                                                   GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+        g_object_unref (provider);
+
+        g_signal_connect_swapped (self->stack, "size-allocate", G_CALLBACK (um_carousel_move_arrow), self);
 }
diff --git a/panels/user-accounts/user-accounts.gresource.xml 
b/panels/user-accounts/user-accounts.gresource.xml
index 4bedc2d..fd960bc 100644
--- a/panels/user-accounts/user-accounts.gresource.xml
+++ b/panels/user-accounts/user-accounts.gresource.xml
@@ -8,6 +8,7 @@
     <file alias="history-dialog.ui" preprocess="xml-stripblanks">data/history-dialog.ui</file>
     <file alias="user-accounts-dialog.ui" preprocess="xml-stripblanks">data/user-accounts-dialog.ui</file>
     <file alias="carousel.ui" preprocess="xml-stripblanks">data/carousel.ui</file>
+    <file alias="carousel.css">data/carousel.css</file>
     <file alias="left-index-finger.png">data/icons/left-index-finger.png</file>
     <file alias="left-middle-finger.png">data/icons/left-middle-finger.png</file>
     <file alias="left-little-finger.png">data/icons/left-little-finger.png</file>


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