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:
parent
011cbc0c08
commit
3a84720fb0
4 changed files with 183 additions and 45 deletions
20
panels/user-accounts/data/carousel.css
Normal file
20
panels/user-accounts/data/carousel.css
Normal 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;
|
||||||
|
}
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue