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,51 +18,91 @@
</object> </object>
</child> </child>
<child type="overlay"> <child type="overlay">
<object class="GtkBox"> <object class="GtkOverlay">
<property name="visible">True</property> <property name="visible">True</property>
<property name="orientation">horizontal</property>
<property name="border_width">12</property>
<child> <child>
<object class="GtkButton" id="go_back_button"> <object class="GtkBox">
<property name="visible">False</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
<property name="valign">center</property> <property name="border_width">12</property>
<style>
<class name="circular"/>
</style>
<child> <child>
<object class="GtkImage"> <object class="GtkButton" id="go_back_button">
<property name="visible">True</property> <property name="visible">False</property>
<property name="can_focus">False</property> <property name="can_focus">True</property>
<property name="icon-size">4</property> <property name="valign">center</property>
<property name="icon_name">go-previous-symbolic</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> </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> </child>
<signal name="clicked" handler="um_carousel_goto_previous_page" object="UmCarousel" swapped="no"/>
</object> </object>
<packing>
<property name="pack_type">start</property>
</packing>
</child> </child>
<child> <child type="overlay">
<object class="GtkButton" id="go_next_button"> <object class="GtkBox">
<property name="can_focus">True</property> <property name="visible">True</property>
<property name="valign">center</property> <property name="valign">GTK_ALIGN_END</property>
<style> <style>
<class name="circular"/> <class name="carousel-arrow-container"/>
</style> </style>
<child> <child>
<object class="GtkImage"> <object class="GtkOverlay">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <child>
<property name="icon-size">4</property> <object class="GtkBox" id="arrow">
<property name="icon_name">go-next-symbolic</property> <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> </object>
</child> </child>
<signal name="clicked" handler="um_carousel_goto_next_page" object="UmCarousel" swapped="no"/>
</object> </object>
<packing> <packing>
<property name="pack_type">end</property> <property name="pass-through">True</property>
</packing> </packing>
</child> </child>
</object> </object>

View file

@ -23,6 +23,8 @@
#include <glib-object.h> #include <glib-object.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#define ARROW_SIZE 20
struct _UmCarouselItem { struct _UmCarouselItem {
GtkRadioButton parent; GtkRadioButton parent;
@ -55,11 +57,14 @@ struct _UmCarousel {
gint visible_page; gint visible_page;
UmCarouselItem *selected_item; UmCarouselItem *selected_item;
GtkWidget *last_box; GtkWidget *last_box;
GtkWidget *arrow;
/* Widgets */ /* Widgets */
GtkStack *stack; GtkStack *stack;
GtkWidget *go_back_button; GtkWidget *go_back_button;
GtkWidget *go_next_button; GtkWidget *go_next_button;
GtkStyleProvider *provider;
}; };
G_DEFINE_TYPE (UmCarousel, um_carousel, GTK_TYPE_REVEALER) G_DEFINE_TYPE (UmCarousel, um_carousel, GTK_TYPE_REVEALER)
@ -73,6 +78,58 @@ static guint signals[NUM_SIGNALS] = { 0, };
#define ITEMS_PER_PAGE 3 #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 static gint
get_last_page_number (UmCarousel *self) get_last_page_number (UmCarousel *self)
{ {
@ -121,15 +178,27 @@ um_carousel_find_item (UmCarousel *self,
return NULL; 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 void
um_carousel_select_item (UmCarousel *self, um_carousel_select_item (UmCarousel *self,
UmCarouselItem *item) UmCarouselItem *item)
{ {
gchar *page_name; gchar *page_name;
self->selected_item = item; on_item_toggled (item, NULL, self);
g_signal_emit (self, signals[ITEM_ACTIVATED], 0, self->selected_item);
self->visible_page = item->page; self->visible_page = item->page;
page_name = g_strdup_printf ("%d", self->visible_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); 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 static void
um_carousel_add (GtkContainer *container, um_carousel_add (GtkContainer *container,
GtkWidget *widget) GtkWidget *widget)
@ -228,6 +285,10 @@ um_carousel_add (GtkContainer *container,
gtk_widget_show_all (self->last_box); gtk_widget_show_all (self->last_box);
update_buttons_visibility (self); 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 void
@ -240,6 +301,7 @@ um_carousel_purge_items (UmCarousel *self)
g_list_free (self->children); g_list_free (self->children);
self->children = NULL; self->children = NULL;
self->visible_page = 0; self->visible_page = 0;
self->selected_item = NULL;
} }
UmCarousel * 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, stack);
gtk_widget_class_bind_template_child (wclass, UmCarousel, go_back_button); 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, 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_previous_page);
gtk_widget_class_bind_template_callback (wclass, um_carousel_goto_next_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 static void
um_carousel_init (UmCarousel *self) um_carousel_init (UmCarousel *self)
{ {
GtkStyleProvider *provider;
gtk_widget_init_template (GTK_WIDGET (self)); 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="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="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.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-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-middle-finger.png">data/icons/left-middle-finger.png</file>
<file alias="left-little-finger.png">data/icons/left-little-finger.png</file> <file alias="left-little-finger.png">data/icons/left-little-finger.png</file>