user-accounts: Draw arrow in UmCarousel

The arrow is drawn using CSS.

https://bugzilla.gnome.org/show_bug.cgi?id=767065
This commit is contained in:
Felipe Borges 2016-12-18 13:57:03 +01:00
parent 011cbc0c08
commit 3a84720fb0
4 changed files with 183 additions and 45 deletions

View file

@ -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;
}

View file

@ -18,9 +18,12 @@
</object>
</child>
<child type="overlay">
<object class="GtkOverlay">
<property name="visible">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">horizontal</property>
<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
<property name="border_width">12</property>
<child>
<object class="GtkButton" id="go_back_button">
@ -41,7 +44,7 @@
<signal name="clicked" handler="um_carousel_goto_previous_page" object="UmCarousel" swapped="no"/>
</object>
<packing>
<property name="pack_type">start</property>
<property name="pack_type">GTK_PACK_START</property>
</packing>
</child>
<child>
@ -62,7 +65,44 @@
<signal name="clicked" handler="um_carousel_goto_next_page" object="UmCarousel" swapped="no"/>
</object>
<packing>
<property name="pack_type">end</property>
<property name="pack_type">GTK_PACK_END</property>
</packing>
</child>
</object>
</child>
<child type="overlay">
<object class="GtkBox">
<property name="visible">True</property>
<property name="valign">GTK_ALIGN_END</property>
<style>
<class name="carousel-arrow-container"/>
</style>
<child>
<object class="GtkOverlay">
<property name="visible">True</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>
</object>
<packing>
<property name="pass-through">True</property>
</packing>
</child>
</object>

View file

@ -23,6 +23,8 @@
#include <glib-object.h>
#include <gtk/gtk.h>
#define ARROW_SIZE 20
struct _UmCarouselItem {
GtkRadioButton parent;
@ -55,11 +57,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)
{
@ -121,15 +178,27 @@ um_carousel_find_item (UmCarousel *self,
return NULL;
}
static void
on_item_toggled (UmCarouselItem *item,
GdkEvent *event,
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, NULL, self);
self->visible_page = item->page;
page_name = g_strdup_printf ("%d", self->visible_page);
@ -181,18 +250,6 @@ um_carousel_goto_next_page (GtkWidget *button,
um_carousel_select_item_at_index (self, self->visible_page * ITEMS_PER_PAGE);
}
static void
on_item_toggled (UmCarouselItem *item,
GdkEvent *event,
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)
@ -228,6 +285,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
@ -240,6 +301,7 @@ um_carousel_purge_items (UmCarousel *self)
g_list_free (self->children);
self->children = NULL;
self->visible_page = 0;
self->selected_item = NULL;
}
UmCarousel *
@ -260,6 +322,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);
@ -279,5 +342,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);
}

View file

@ -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>