[gnome-control-center/wip/feborges/new-users-panel: 261/264] user-accounts: Introduce UmCarousel



commit d1edc14e1356bc3e9ed11d2a99f909dc703f7020
Author: Felipe Borges <felipeborges gnome org>
Date:   Tue Nov 15 14:40:54 2016 +0100

    user-accounts: Introduce UmCarousel
    
    UmCarousel is an horizontal container that contains UmCarouselItem
    children. These items are paginated 3 at 3 at the time.
    
    UmCarousel intents to act as controller for content containers. It
    emitis the "item-activated" signal whenever an UmCarouselItem gets
    activated (clicked).
    
    It automatically activates the first UmCarouselItem of the current
    vsible page.
    
    The visibility of the go-back and go-next button is automatically
    set based on the number of children.
    
    These changes are according to the new User Accounts panel mockups
    at https://wiki.gnome.org/Design/SystemSettings/UserAccounts
    
    https://bugzilla.gnome.org/show_bug.cgi?id=767065

 panels/user-accounts/Makefile.am                  |    2 +
 panels/user-accounts/data/carousel.ui             |   77 +++
 panels/user-accounts/data/user-accounts-dialog.ui |  691 ++++++++++-----------
 panels/user-accounts/um-carousel.c                |  278 +++++++++
 panels/user-accounts/um-carousel.h                |   51 ++
 panels/user-accounts/um-user-panel.c              |  585 +++++-------------
 panels/user-accounts/user-accounts.gresource.xml  |    1 +
 7 files changed, 879 insertions(+), 806 deletions(-)
---
diff --git a/panels/user-accounts/Makefile.am b/panels/user-accounts/Makefile.am
index eff4d67..819b9b0 100644
--- a/panels/user-accounts/Makefile.am
+++ b/panels/user-accounts/Makefile.am
@@ -31,6 +31,8 @@ libuser_accounts_la_SOURCES =         \
        um-account-type.c               \
        um-account-dialog.h             \
        um-account-dialog.c             \
+       um-carousel.h                   \
+       um-carousel.c                   \
        um-password-dialog.h            \
        um-password-dialog.c            \
        pw-utils.h                      \
diff --git a/panels/user-accounts/data/carousel.ui b/panels/user-accounts/data/carousel.ui
new file mode 100644
index 0000000..ab49bdc
--- /dev/null
+++ b/panels/user-accounts/data/carousel.ui
@@ -0,0 +1,77 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- interface-requires gtk+ 3.8 -->
+  <template class="UmCarousel" parent="GtkBox">
+    <style>
+      <class name="location-bar"/>
+    </style>
+    <child>
+      <object class="GtkOverlay">
+        <property name="visible">True</property>
+        <property name="hexpand">True</property>
+        <property name="border_width">30</property>
+        <child>
+          <object class="GtkStack" id="stack">
+            <property name="visible">True</property>
+            <property name="valign">GTK_ALIGN_CENTER</property>
+            <property name="transition_type">GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT</property>
+            <property name="transition_duration">400</property>
+          </object>
+        </child>
+        <child type="overlay">
+          <object class="GtkBox">
+            <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>
+                <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">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">end</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="pass-through">True</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/panels/user-accounts/data/user-accounts-dialog.ui 
b/panels/user-accounts/data/user-accounts-dialog.ui
index 11cae9d..4759c9b 100644
--- a/panels/user-accounts/data/user-accounts-dialog.ui
+++ b/panels/user-accounts/data/user-accounts-dialog.ui
@@ -95,419 +95,376 @@
           <object class="GtkVBox" id="accounts-vbox">
             <property name="visible">True</property>
             <property name="orientation">vertical</property>
-            <property name="border_width">12</property>
+            <property name="border_width">0</property>
             <child>
-              <object class="GtkHBox" id="hbox2">
+              <object class="GtkRevealer" id="carousel-revealer">
                 <property name="visible">True</property>
-                <property name="spacing">18</property>
+                <property name="transition_duration">400</property>
+                <property name="valign">GTK_ALIGN_START</property>
                 <child>
-                  <object class="GtkVBox" id="userlist-vbox">
+                  <object class="UmCarousel" id="carousel">
                     <property name="visible">True</property>
-                    <property name="orientation">vertical</property>
-                    <property name="spacing">0</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="fill">False</property>
+                <property name="expand">False</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkGrid" id="user-options">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="column_spacing">10</property>
+                <property name="row_spacing">10</property>
+                <property name="border_width">30</property>
+                <property name="halign">GTK_ALIGN_CENTER</property>
+                <child>
+                  <object class="GtkButton" id="account-fingerprint-button">
+                    <property name="visible">True</property>
+                    <property name="hexpand">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">5</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox" id="account-type-box">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="sensitive">False</property>
+                    <style>
+                      <class name="linked"/>
+                    </style>
                     <child>
-                      <object class="GtkScrolledWindow" id="list-scrolledwindow">
+                      <object class="GtkRadioButton" id="account-type-standard">
                         <property name="visible">True</property>
                         <property name="can_focus">True</property>
-                        <property name="hscrollbar_policy">never</property>
-                        <property name="vscrollbar_policy">automatic</property>
-                        <property name="shadow_type">in</property>
-                        <child>
-                          <object class="GtkTreeView" id="list-treeview">
-                            <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="headers_visible">False</property>
-                          </object>
-                        </child>
+                        <property name="label" translatable="yes">Standard</property>
+                        <property name="draw_indicator">False</property>
+                        <property name="hexpand">True</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkRadioButton" id="account-type-admin">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="label" translatable="yes">Administrator</property>
+                        <property name="draw_indicator">False</property>
+                        <property name="group">account-type-standard</property>
+                        <property name="hexpand">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">1</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="account-type-label">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">Account _Type</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">account-type-box</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">1</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="orientation">GTK_ORIENTATION_VERTICAL</property>
+                    <child>
+                      <object class="GtkEntry" id="full-name-entry">
+                        <property name="visible">True</property>
+                        <property name="width-chars">30</property>
+                        <property name="max-width-chars">30</property>
+                        <property name="valign">GTK_ALIGN_CENTER</property>
                       </object>
                       <packing>
-                        <property name="expand">True</property>
                         <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">0</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="password-label">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">_Password</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">account-password-button</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">3</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="account-password-button">
+                    <property name="visible">True</property>
+                    <property name="hexpand">True</property>
+                    <style>
+                      <class name="text-button"/>
+                    </style>
+                    <child>
+                      <object class="GtkLabel" id="account-password-button-label">
+                        <property name="visible">True</property>
+                        <property name="halign">GTK_ALIGN_START</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">3</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="autologin-label">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">A_utomatic Login</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">autologin-switch</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">4</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox" id="autologin-box">
+                    <property name="visible">True</property>
+                    <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+                    <child>
+                      <object class="GtkSwitch" id="autologin-switch">
+                        <property name="visible">True</property>
+                        <property name="valign">GTK_ALIGN_CENTER</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
                         <property name="position">0</property>
                       </packing>
                     </child>
                   </object>
                   <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">4</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkVBox" id="main-user-vbox">
+                  <object class="GtkLabel" id="account-fingerprint-label">
                     <property name="visible">True</property>
-                    <property name="sensitive">False</property>
-                    <property name="orientation">vertical</property>
-                    <property name="spacing">6</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">_Fingerprint Login</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">account-fingerprint-button</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">5</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkBox">
+                    <property name="visible">True</property>
+                    <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
                     <child>
-                      <object class="GtkGrid" id="grid1">
+                      <object class="GtkLabel" id="label4">
                         <property name="visible">True</property>
-                        <property name="can_focus">False</property>
-                        <property name="column_spacing">10</property>
-                        <property name="row_spacing">10</property>
-                        <child>
-                          <object class="GtkButton" id="account-fingerprint-button">
-                            <property name="visible">True</property>
-                            <property name="hexpand">True</property>
-                          </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="top_attach">5</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkBox" id="account-type-box">
-                            <property name="visible">True</property>
-                            <property name="can_focus">False</property>
-                            <property name="sensitive">False</property>
-                            <style>
-                              <class name="linked"/>
-                            </style>
-                            <child>
-                              <object class="GtkRadioButton" id="account-type-standard">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="label" translatable="yes">Standard</property>
-                                <property name="draw_indicator">False</property>
-                                <property name="hexpand">True</property>
-                              </object>
-                            </child>
-                            <child>
-                              <object class="GtkRadioButton" id="account-type-admin">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="label" translatable="yes">Administrator</property>
-                                <property name="draw_indicator">False</property>
-                                <property name="group">account-type-standard</property>
-                                <property name="hexpand">True</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="top_attach">1</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="account-type-label">
-                            <property name="visible">True</property>
-                            <property name="xalign">1</property>
-                            <property name="label" translatable="yes">Account _Type</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">account-type-box</property>
-                            <style>
-                              <class name="dim-label"/>
-                            </style>
-                          </object>
-                          <packing>
-                            <property name="left_attach">0</property>
-                            <property name="top_attach">1</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkVBox" id="vbox10">
-                            <property name="visible">True</property>
-                            <property name="orientation">vertical</property>
-                            <child>
-                              <object class="GtkEntry" id="full-name-entry">
-                                <property name="visible">True</property>
-                                <property name="width-chars">30</property>
-                                <property name="max-width-chars">30</property>
-                                <property name="valign">GTK_ALIGN_CENTER</property>
-                              </object>
-                              <packing>
-                                <property name="fill">True</property>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="top_attach">0</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="password-label">
-                            <property name="visible">True</property>
-                            <property name="xalign">1</property>
-                            <property name="label" translatable="yes">_Password</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">account-password-button</property>
-                            <style>
-                              <class name="dim-label"/>
-                            </style>
-                          </object>
-                          <packing>
-                            <property name="left_attach">0</property>
-                            <property name="top_attach">3</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkButton" id="account-password-button">
-                            <property name="visible">True</property>
-                            <property name="hexpand">True</property>
-                            <style>
-                              <class name="text-button"/>
-                            </style>
-                            <child>
-                              <object class="GtkLabel" id="account-password-button-label">
-                                <property name="visible">True</property>
-                                <property name="halign">GTK_ALIGN_START</property>
-                              </object>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="top_attach">3</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="autologin-label">
-                            <property name="visible">True</property>
-                            <property name="xalign">1</property>
-                            <property name="label" translatable="yes">A_utomatic Login</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">autologin-switch</property>
-                            <style>
-                              <class name="dim-label"/>
-                            </style>
-                          </object>
-                          <packing>
-                            <property name="left_attach">0</property>
-                            <property name="top_attach">4</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkBox" id="autologin-box">
-                            <property name="visible">True</property>
-                            <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
-                            <child>
-                              <object class="GtkSwitch" id="autologin-switch">
-                                <property name="visible">True</property>
-                                <property name="valign">GTK_ALIGN_CENTER</property>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">0</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <placeholder/>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="top_attach">4</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="account-fingerprint-label">
-                            <property name="visible">True</property>
-                            <property name="xalign">1</property>
-                            <property name="label" translatable="yes">_Fingerprint Login</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">account-fingerprint-button</property>
-                            <style>
-                              <class name="dim-label"/>
-                            </style>
-                          </object>
-                          <packing>
-                            <property name="left_attach">0</property>
-                            <property name="top_attach">5</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkHBox" id="hbox5">
-                            <property name="visible">True</property>
-                            <child>
-                              <object class="GtkLabel" id="label4">
-                                <property name="visible">True</property>
-                                <property name="hexpand">True</property>
-                              </object>
-                              <packing>
-                                <property name="expand">True</property>
-                                <property name="fill">True</property>
-                                <property name="position">0</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="UmUserImage" id="user-icon-image">
-                                <property name="visible">True</property>
-                                <property name="icon_name">avatar-default</property>
-                                <property name="icon-size">6</property>
-                                <property name="halign">end</property>
-                                <child internal-child="accessible">
-                                  <object class="AtkObject" id="user-icon-image-a11y">
-                                    <property name="accessible-name" translatable="yes">User Icon</property>
-                                  </object>
-                                </child>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">1</property>
-                              </packing>
-                            </child>
-                            <child>
-                              <object class="GtkToggleButton" id="user-icon-button">
-                                <property name="visible">True</property>
-                                <property name="can_focus">True</property>
-                                <property name="receives_default">True</property>
-                                <property name="relief">none</property>
-                                <child internal-child="accessible">
-                                  <object class="AtkObject" id="user-icon-image2-a11y">
-                                    <property name="accessible-name" translatable="yes">User Icon</property>
-                                  </object>
-                                </child>
-                                <child>
-                                  <object class="UmUserImage" id="user-icon-image2">
-                                    <property name="visible">True</property>
-                                    <property name="icon_name">avatar-default</property>
-                                    <property name="icon-size">6</property>
-                                  </object>
-                                </child>
-                              </object>
-                              <packing>
-                                <property name="expand">False</property>
-                                <property name="fill">False</property>
-                                <property name="position">2</property>
-                              </packing>
-                            </child>
-                          </object>
-                          <packing>
-                            <property name="left_attach">0</property>
-                            <property name="top_attach">0</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkLabel" id="language-label">
-                            <property name="visible">True</property>
-                            <property name="xalign">1</property>
-                            <property name="label" translatable="yes">_Language</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">account-language-button</property>
-                            <style>
-                              <class name="dim-label"/>
-                            </style>
-                          </object>
-                          <packing>
-                            <property name="left_attach">0</property>
-                            <property name="top_attach">2</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
-                        </child>
-                        <child>
-                          <object class="GtkButton" id="account-language-button">
-                            <property name="visible">True</property>
-                            <property name="hexpand">True</property>
-                            <style>
-                              <class name="text-button"/>
-                            </style>
-                            <child>
-                              <object class="GtkLabel" id="account-language-button-label">
-                                <property name="visible">True</property>
-                                <property name="halign">GTK_ALIGN_START</property>
-                              </object>
-                            </child>
+                        <property name="hexpand">True</property>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="UmUserImage" id="user-icon-image">
+                        <property name="visible">True</property>
+                        <property name="icon_name">avatar-default</property>
+                        <property name="icon-size">6</property>
+                        <property name="halign">GTK_ALIGN_END</property>
+                        <child internal-child="accessible">
+                          <object class="AtkObject" id="user-icon-image-a11y">
+                            <property name="accessible-name" translatable="yes">User Icon</property>
                           </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="top_attach">2</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
                         </child>
-                        <child>
-                          <object class="GtkLabel" id="last-login-label">
-                            <property name="visible">True</property>
-                            <property name="xalign">1</property>
-                            <property name="label" translatable="yes">Last Login</property>
-                            <property name="use_underline">True</property>
-                            <property name="mnemonic_widget">last-login-button</property>
-                            <style>
-                              <class name="dim-label"/>
-                            </style>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkToggleButton" id="user-icon-button">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">True</property>
+                        <property name="relief">GTK_RELIEF_NONE</property>
+                        <child internal-child="accessible">
+                          <object class="AtkObject" id="user-icon-image2-a11y">
+                            <property name="accessible-name" translatable="yes">User Icon</property>
                           </object>
-                          <packing>
-                            <property name="left_attach">0</property>
-                            <property name="top_attach">6</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
                         </child>
                         <child>
-                          <object class="GtkButton" id="last-login-button">
+                          <object class="UmUserImage" id="user-icon-image2">
                             <property name="visible">True</property>
-                            <property name="can_focus">True</property>
-                            <property name="receives_default">True</property>
-                            <style>
-                              <class name="text-button"/>
-                            </style>
-                            <child>
-                              <object class="GtkLabel" id="last-login-button-label">
-                                <property name="visible">True</property>
-                                <property name="halign">GTK_ALIGN_START</property>
-                              </object>
-                            </child>
+                            <property name="icon_name">avatar-default</property>
+                            <property name="icon-size">6</property>
                           </object>
-                          <packing>
-                            <property name="left_attach">1</property>
-                            <property name="top_attach">6</property>
-                            <property name="width">1</property>
-                            <property name="height">1</property>
-                          </packing>
                         </child>
                       </object>
                       <packing>
                         <property name="expand">False</property>
-                        <property name="fill">True</property>
-                        <property name="position">0</property>
+                        <property name="fill">False</property>
+                        <property name="position">2</property>
                       </packing>
                     </child>
                   </object>
                   <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">1</property>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">0</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkButton" id="remove-user-toolbutton">
+                  <object class="GtkLabel" id="language-label">
                     <property name="visible">True</property>
-                    <property name="can_focus">False</property>
-                    <property name="halign">GTK_ALIGN_END</property>
-                    <property name="valign">GTK_ALIGN_END</property>
-                    <property name="label" translatable="yes">Remove Account</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">_Language</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">account-language-button</property>
+                    <style>
+                      <class name="dim-label"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">2</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="account-language-button">
+                    <property name="visible">True</property>
+                    <property name="hexpand">True</property>
+                    <style>
+                      <class name="text-button"/>
+                    </style>
+                    <child>
+                      <object class="GtkLabel" id="account-language-button-label">
+                        <property name="visible">True</property>
+                        <property name="halign">GTK_ALIGN_START</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">2</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="last-login-label">
+                    <property name="visible">True</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">Last Login</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">last-login-button</property>
                     <style>
-                      <class name="destructive-action"/>
+                      <class name="dim-label"/>
                     </style>
                   </object>
                   <packing>
-                    <property name="position">2</property>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">6</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
                   </packing>
                 </child>
+                <child>
+                  <object class="GtkButton" id="last-login-button">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <style>
+                      <class name="text-button"/>
+                    </style>
+                    <child>
+                      <object class="GtkLabel" id="last-login-button-label">
+                        <property name="visible">True</property>
+                        <property name="halign">GTK_ALIGN_START</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">6</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkButton" id="remove-user-toolbutton">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="halign">GTK_ALIGN_END</property>
+                <property name="valign">GTK_ALIGN_END</property>
+                <property name="border_width">20</property>
+                <property name="label" translatable="yes">Remove Account</property>
+                <style>
+                  <class name="destructive-action"/>
+                </style>
               </object>
             </child>
           </object>
diff --git a/panels/user-accounts/um-carousel.c b/panels/user-accounts/um-carousel.c
new file mode 100644
index 0000000..fe8df2f
--- /dev/null
+++ b/panels/user-accounts/um-carousel.c
@@ -0,0 +1,278 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2016 (c) Red Hat, Inc,
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Felipe Borges <felipeborges gnome org>
+ */
+
+#include "um-carousel.h"
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+struct _UmCarouselItem {
+        GtkToggleButton parent;
+
+        gint page;
+};
+
+G_DEFINE_TYPE (UmCarouselItem, um_carousel_item, GTK_TYPE_TOGGLE_BUTTON)
+
+GtkWidget *
+um_carousel_item_new (void)
+{
+        return g_object_new (UM_TYPE_CAROUSEL_ITEM, NULL);
+}
+
+static void
+um_carousel_item_class_init (UmCarouselItemClass *klass)
+{
+}
+
+static void
+um_carousel_item_init (UmCarouselItem *self)
+{
+}
+
+struct _UmCarousel {
+        GtkBox parent;
+
+        GList *children;
+        gint visible_page;
+        UmCarouselItem *selected_item;
+        GtkWidget *last_box;
+
+        /* Widgets */
+        GtkStack *stack;
+        GtkWidget *go_back_button;
+        GtkWidget *go_next_button;
+};
+
+G_DEFINE_TYPE (UmCarousel, um_carousel, GTK_TYPE_BOX)
+
+enum {
+        ITEM_ACTIVATED,
+        NUM_SIGNALS
+};
+
+static guint signals[NUM_SIGNALS] = { 0, };
+
+#define ITEMS_PER_PAGE 3
+
+static gint
+get_last_page_number (UmCarousel *self)
+{
+        if (g_list_length (self->children) == 0)
+                return 0;
+
+        return ((g_list_length (self->children) - 1) / ITEMS_PER_PAGE);
+}
+
+static void
+update_buttons_visibility (UmCarousel *self)
+{
+        gtk_widget_set_visible (self->go_back_button, (self->visible_page > 0));
+        gtk_widget_set_visible (self->go_next_button, (self->visible_page < get_last_page_number (self)));
+}
+
+/**
+ * um_carousel_find_item:
+ * @carousel: an UmCarousel instance
+ * @data: user data passed to the comparation function
+ * @func: the function to call for each element.
+ *      It should return 0 when the desired element is found
+ *
+ * Finds an UmCarousel item using the supplied function to find the
+ * desired element.
+ * Ideally useful for matching a model object and its correspondent
+ * widget.
+ *
+ * Returns: the found UmCarouselItem, or %NULL if it is not found
+ */
+UmCarouselItem*
+um_carousel_find_item (UmCarousel    *self,
+                       gconstpointer  data,
+                       GCompareFunc   func)
+{
+        GList *list;
+
+        list = self->children;
+        while (list!= NULL)
+        {
+                if (!func (list->data, data))
+                        return list->data;
+                list = list->next;
+        }
+
+        return NULL;
+}
+
+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);
+
+        self->visible_page = item->page;
+        page_name = g_strdup_printf ("%d", self->visible_page);
+        gtk_stack_set_visible_child_name (self->stack, page_name);
+
+        g_free (page_name);
+
+        update_buttons_visibility (self);
+}
+
+static void
+um_carousel_select_item_at_index (UmCarousel *self,
+                                  gint        index)
+{
+        GList *l = NULL;
+
+        l = g_list_nth (self->children, index);
+        um_carousel_select_item (self, l->data);
+}
+
+static void
+um_carousel_goto_previous_page (GtkWidget *button,
+                                gpointer   user_data)
+{
+        UmCarousel *self = UM_CAROUSEL (user_data);
+
+        self->visible_page--;
+        if (self->visible_page < 0)
+                self->visible_page = 0;
+
+        /* Select first item of the page */
+        um_carousel_select_item_at_index (self, self->visible_page * ITEMS_PER_PAGE);
+}
+
+static void
+um_carousel_goto_next_page (GtkWidget *button,
+                            gpointer   user_data)
+{
+        UmCarousel *self = UM_CAROUSEL (user_data);
+        gint last_page;
+
+        last_page = get_last_page_number (self);
+
+        self->visible_page++;
+        if (self->visible_page > last_page)
+                self->visible_page = last_page;
+
+        /* Select first item of the page */
+        um_carousel_select_item_at_index (self, self->visible_page * ITEMS_PER_PAGE);
+}
+
+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)
+{
+        UmCarousel *self = UM_CAROUSEL (container);
+        gboolean last_box_is_full;
+
+        if (!UM_IS_CAROUSEL_ITEM (widget)) {
+                GTK_CONTAINER_CLASS (um_carousel_parent_class)->add (container, widget);
+                return;
+        }
+
+        gtk_style_context_add_class (gtk_widget_get_style_context (widget), "menu");
+        gtk_button_set_relief (GTK_BUTTON (widget), GTK_RELIEF_NONE);
+
+        self->children = g_list_append (self->children, widget);
+        UM_CAROUSEL_ITEM (widget)->page = get_last_page_number (self);
+        g_signal_connect (widget, "toggled", G_CALLBACK (on_item_toggled), self);
+
+        last_box_is_full = ((g_list_length (self->children) - 1) % ITEMS_PER_PAGE == 0);
+        if (last_box_is_full) {
+                gchar *page;
+
+                page = g_strdup_printf ("%d", UM_CAROUSEL_ITEM (widget)->page);
+                self->last_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+                gtk_stack_add_named (self->stack, self->last_box, page);
+        }
+
+        gtk_box_pack_start (GTK_BOX (self->last_box), widget, TRUE, FALSE, 10);
+        gtk_widget_show_all (self->last_box);
+
+        update_buttons_visibility (self);
+}
+
+void
+um_carousel_purge_items (UmCarousel *self)
+{
+        gtk_container_forall (GTK_CONTAINER (self->stack),
+                              (GtkCallback) gtk_widget_destroy,
+                              NULL);
+
+        g_list_free (self->children);
+        self->children = NULL;
+        self->visible_page = 0;
+}
+
+UmCarousel *
+um_carousel_new (void)
+{
+        return g_object_new (UM_TYPE_CAROUSEL, NULL);
+}
+
+static void
+um_carousel_class_init (UmCarouselClass *klass)
+{
+        GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass);
+        GtkContainerClass *container_class = GTK_CONTAINER_CLASS (klass);
+
+        gtk_widget_class_set_template_from_resource (wclass,
+                                                     "/org/gnome/control-center/user-accounts/carousel.ui");
+
+        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_callback (wclass, um_carousel_goto_previous_page);
+        gtk_widget_class_bind_template_callback (wclass, um_carousel_goto_next_page);
+
+        container_class->add = um_carousel_add;
+
+        signals[ITEM_ACTIVATED] = g_signal_new ("item-activated",
+                                                UM_TYPE_CAROUSEL,
+                                                G_SIGNAL_RUN_LAST,
+                                                0,
+                                                NULL, NULL,
+                                                g_cclosure_marshal_VOID__OBJECT,
+                                                G_TYPE_NONE, 1,
+                                                UM_TYPE_CAROUSEL_ITEM);
+}
+
+static void
+um_carousel_init (UmCarousel *self)
+{
+        gtk_widget_init_template (GTK_WIDGET (self));
+}
diff --git a/panels/user-accounts/um-carousel.h b/panels/user-accounts/um-carousel.h
new file mode 100644
index 0000000..669b377
--- /dev/null
+++ b/panels/user-accounts/um-carousel.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2016 (c) Red Hat, Inc,
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author: Felipe Borges <felipeborges gnome org>
+ */
+
+#ifndef UM_CAROUSEL_H
+#define UM_CAROUSEL_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define UM_TYPE_CAROUSEL_ITEM (um_carousel_item_get_type ())
+
+G_DECLARE_FINAL_TYPE (UmCarouselItem, um_carousel_item, UM, CAROUSEL_ITEM, GtkToggleButton)
+
+#define UM_TYPE_CAROUSEL (um_carousel_get_type())
+
+G_DECLARE_FINAL_TYPE (UmCarousel, um_carousel, UM, CAROUSEL, GtkBox)
+
+GtkWidget       *um_carousel_item_new    (void);
+
+UmCarousel      *um_carousel_new         (void);
+
+void             um_carousel_purge_items (UmCarousel     *self);
+
+UmCarouselItem  *um_carousel_find_item   (UmCarousel     *self,
+                                          gconstpointer   data,
+                                          GCompareFunc    func);
+
+void             um_carousel_select_item (UmCarousel     *self,
+                                          UmCarouselItem *item);
+
+G_END_DECLS
+
+#endif /* UM_CAROUSEL_H */
diff --git a/panels/user-accounts/um-user-panel.c b/panels/user-accounts/um-user-panel.c
index 671a0c8..37148ad 100644
--- a/panels/user-accounts/um-user-panel.c
+++ b/panels/user-accounts/um-user-panel.c
@@ -44,6 +44,7 @@
 #include "um-account-dialog.h"
 #include "cc-language-chooser.h"
 #include "um-password-dialog.h"
+#include "um-carousel.h"
 #include "um-photo-dialog.h"
 #include "um-fingerprint-dialog.h"
 #include "um-utils.h"
@@ -71,6 +72,8 @@ struct _CcUserPanelPrivate {
 
         GtkWidget *headerbar_buttons;
         GtkWidget *main_box;
+        UmCarousel *carousel;
+        ActUser *selected_user;
         GPermission *permission;
         GtkWidget *language_chooser;
 
@@ -79,7 +82,6 @@ struct _CcUserPanelPrivate {
         UmHistoryDialog *history_dialog;
 
         gint other_accounts;
-        GtkTreeIter *other_iter;
 
         UmAccountDialog *account_dialog;
 };
@@ -93,16 +95,6 @@ get_widget (CcUserPanelPrivate *d, const char *name)
 #define PAGE_LOCK "_lock"
 #define PAGE_ADDUSER "_adduser"
 
-enum {
-        USER_COL,
-        NAME_COL,
-        USER_ROW_COL,
-        TITLE_COL,
-        HEADING_ROW_COL,
-        SORT_KEY_COL,
-        NUM_USER_LIST_COLS
-};
-
 static void show_restart_notification (CcUserPanelPrivate *d, const gchar *locale);
 
 typedef struct {
@@ -146,21 +138,7 @@ show_error_dialog (CcUserPanelPrivate *d,
 static ActUser *
 get_selected_user (CcUserPanelPrivate *d)
 {
-        GtkTreeView *tv;
-        GtkTreeIter iter;
-        GtkTreeSelection *selection;
-        GtkTreeModel *model;
-        ActUser *user;
-
-        tv = (GtkTreeView *)get_widget (d, "list-treeview");
-        selection = gtk_tree_view_get_selection (tv);
-
-        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
-                gtk_tree_model_get (model, &iter, USER_COL, &user, -1);
-                return user;
-        }
-
-        return NULL;
+        return d->selected_user;
 }
 
 static const gchar *
@@ -175,205 +153,180 @@ get_real_or_user_name (ActUser *user)
   return name;
 }
 
-static char *
-get_name_col_str (ActUser *user)
+static void show_user (ActUser *user, CcUserPanelPrivate *d);
+
+static void
+set_selected_user (UmCarousel *carousel, UmCarouselItem *item, CcUserPanelPrivate *d)
 {
-        return g_markup_printf_escaped ("<b>%s</b>\n<small>%s</small>",
-                                        get_real_or_user_name (user),
-                                        act_user_get_user_name (user));
+        uid_t uid;
+
+        g_clear_object (&d->selected_user);
+
+        uid = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "uid"));
+        d->selected_user = act_user_manager_get_user_by_id (d->um, uid);
+
+        if (d->selected_user != NULL) {
+                show_user (d->selected_user, d);
+        }
 }
 
-static void show_user (ActUser *user, CcUserPanelPrivate *d);
+static GtkWidget *
+create_carousel_entry (CcUserPanelPrivate *d, ActUser *user)
+{
+        GtkWidget *box, *widget;
+
+        box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
+
+        widget = um_user_image_new ();
+        um_user_image_set_user (UM_USER_IMAGE (widget), user);
+        gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
+
+        widget = gtk_label_new (get_real_or_user_name (user));
+        gtk_box_pack_start (GTK_BOX (box), widget, FALSE, TRUE, 0);
+
+        return box;
+}
 
 static void
 user_added (ActUserManager *um, ActUser *user, CcUserPanelPrivate *d)
 {
-        GtkWidget *widget;
-        GtkTreeModel *model;
-        GtkListStore *store;
-        GtkTreeIter iter;
-        GtkTreeIter dummy;
-        gchar *text, *title;
-        GtkTreeSelection *selection;
-        gint sort_key;
+        GtkWidget *item, *widget;
+        gboolean show_carousel;
 
         if (act_user_is_system_account (user)) {
                 return;
         }
 
         g_debug ("user added: %d %s\n", act_user_get_uid (user), get_real_or_user_name (user));
-        widget = get_widget (d, "list-treeview");
-        model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget));
-        store = GTK_LIST_STORE (model);
-        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget));
 
-        text = get_name_col_str (user);
+        widget = create_carousel_entry (d, user);
+        item = um_carousel_item_new ();
+        gtk_container_add (GTK_CONTAINER (item), widget);
 
-        if (act_user_get_uid (user) == getuid ()) {
-                sort_key = 1;
-        }
-        else {
+        g_object_set_data (G_OBJECT (item), "uid", GINT_TO_POINTER (act_user_get_uid (user)));
+        gtk_container_add (GTK_CONTAINER (d->carousel), item);
+
+        if (act_user_get_uid (user) != getuid ()) {
                 d->other_accounts++;
-                sort_key = 3;
         }
-        gtk_list_store_append (store, &iter);
 
-        gtk_list_store_set (store, &iter,
-                            USER_COL, user,
-                            NAME_COL, text,
-                            USER_ROW_COL, TRUE,
-                            TITLE_COL, NULL,
-                            HEADING_ROW_COL, FALSE,
-                            SORT_KEY_COL, sort_key,
-                            -1);
-        g_free (text);
+        /* Show heading for other accounts if new one have been added. */
+        show_carousel = (d->other_accounts > 0);
+        widget = get_widget (d, "carousel-revealer");
+        gtk_revealer_set_reveal_child (GTK_REVEALER (widget), show_carousel);
+}
+
+static gint
+sort_users (gconstpointer a, gconstpointer b)
+{
+        ActUser *ua, *ub;
+        gchar *name1, *name2;
+        gint result;
 
-        if (sort_key == 1 &&
-            !gtk_tree_selection_get_selected (selection, &model, &dummy)) {
-                gtk_tree_selection_select_iter (selection, &iter);
+        ua = ACT_USER (a);
+        ub = ACT_USER (b);
+
+        /* Make sure the current user is shown first */
+        if (act_user_get_uid (ua) == getuid ()) {
+                result = -G_MAXINT32;
+        }
+        else if (act_user_get_uid (ub) == getuid ()) {
+                result = G_MAXINT32;
         }
+        else {
+                name1 = g_utf8_collate_key (get_real_or_user_name (ua), -1);
+                name2 = g_utf8_collate_key (get_real_or_user_name (ub), -1);
 
-        /* Show heading for other accounts if new one have been added. */
-        if (d->other_accounts == 1 && sort_key == 3) {
-                title = g_strdup_printf ("<small><span foreground=\"#555555\">%s</span></small>", _("Other 
Accounts"));
-                gtk_list_store_append (store, &iter);
-                gtk_list_store_set (store, &iter,
-                                    TITLE_COL, title,
-                                    HEADING_ROW_COL, TRUE,
-                                    SORT_KEY_COL, 2,
-                                    -1);
-                d->other_iter = gtk_tree_iter_copy (&iter);
-                g_free (title);
+                result = strcmp (name1, name2);
+
+                g_free (name1);
+                g_free (name2);
         }
+
+        return result;
 }
 
 static void
-get_previous_user_row (GtkTreeModel *model,
-                       GtkTreeIter  *iter,
-                       GtkTreeIter  *prev)
+reload_users (CcUserPanelPrivate *d)
 {
-        GtkTreePath *path;
         ActUser *user;
+        GSList *list, *l;
 
-        path = gtk_tree_model_get_path (model, iter);
-        while (gtk_tree_path_prev (path)) {
-                gtk_tree_model_get_iter (model, prev, path);
-                gtk_tree_model_get (model, prev, USER_COL, &user, -1);
-                if (user) {
-                        g_object_unref (user);
-                        break;
-                }
+        um_carousel_purge_items (d->carousel);
+
+        d->other_accounts = 0;
+
+        list = act_user_manager_list_users (d->um);
+        g_debug ("Got %d users\n", g_slist_length (list));
+
+        list = g_slist_sort (list, (GCompareFunc) sort_users);
+        for (l = list; l; l = l->next) {
+                user = l->data;
+                g_debug ("adding user %s\n", get_real_or_user_name (user));
+                user_added (d->um, user, d);
         }
-        gtk_tree_path_free (path);
+        g_slist_free (list);
 }
 
-static gboolean
-get_next_user_row (GtkTreeModel *model,
-                   GtkTreeIter  *iter,
-                   GtkTreeIter  *next)
+static void
+user_removed (ActUserManager *um, ActUser *user, CcUserPanelPrivate *d)
 {
-        ActUser *user;
+        gboolean show_carousel;
 
-        *next = *iter;
-        while (gtk_tree_model_iter_next (model, next)) {
-                gtk_tree_model_get (model, next, USER_COL, &user, -1);
-                if (user) {
-                        g_object_unref (user);
-                        return TRUE;
-                }
-        }
+        d->other_accounts--;
+        show_carousel = (d->other_accounts > 0);
+        gtk_revealer_set_reveal_child (GTK_REVEALER (get_widget (d, "carousel-revealer")),
+                                       show_carousel);
+
+        reload_users (d);
 
-        return FALSE;
+        /* Show the current user */
+        user = act_user_manager_get_user_by_id (d->um, getuid ());
+        show_user (user, d);
 }
 
-static void
-user_removed (ActUserManager *um, ActUser *user, CcUserPanelPrivate *d)
+static gint
+user_compare (gconstpointer i,
+              gconstpointer u)
 {
-        GtkTreeView *tv;
-        GtkTreeModel *model;
-        GtkTreeSelection *selection;
-        GtkListStore *store;
-        GtkTreeIter iter, next;
-        ActUser *u;
-        gint key;
-
-        g_debug ("user removed: %s\n", act_user_get_user_name (user));
-        tv = (GtkTreeView *)get_widget (d, "list-treeview");
-        selection = gtk_tree_view_get_selection (tv);
-        model = gtk_tree_view_get_model (tv);
-        store = GTK_LIST_STORE (model);
-        if (gtk_tree_model_get_iter_first (model, &iter)) {
-                do {
-                        gtk_tree_model_get (model, &iter, USER_COL, &u, SORT_KEY_COL, &key, -1);
-
-                        if (u != NULL) {
-                                if (act_user_get_uid (user) == act_user_get_uid (u)) {
-                                        if (!get_next_user_row (model, &iter, &next))
-                                                get_previous_user_row (model, &iter, &next);
-                                        if (key == 3) {
-                                                d->other_accounts--;
-                                        }
-                                        gtk_list_store_remove (store, &iter);
-                                        gtk_tree_selection_select_iter (selection, &next);
-                                        g_object_unref (u);
-                                        break;
-                                }
-                                g_object_unref (u);
-                        }
-                } while (gtk_tree_model_iter_next (model, &iter));
-        }
+        UmCarouselItem *item;
+        ActUser *user;
+        gint uid_a, uid_b;
+        gint result;
 
-        /* Hide heading for other accounts if last one have been removed. */
-        if (d->other_iter != NULL && d->other_accounts == 0 && key == 3) {
-                gtk_list_store_remove (store, d->other_iter);
-                gtk_tree_iter_free (d->other_iter);
-                d->other_iter = NULL;
-        }
+        item = (UmCarouselItem *) i;
+        user = ACT_USER (u);
+
+        uid_a = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "uid"));
+        uid_b = act_user_get_uid (user);
+
+        result = uid_a - uid_b;
+
+        return result;
 }
 
 static void
 user_changed (ActUserManager *um, ActUser *user, CcUserPanelPrivate *d)
 {
-        GtkTreeView *tv;
-        GtkTreeSelection *selection;
-        GtkTreeModel *model;
-        GtkTreeIter iter;
-        ActUser *current;
-        char *text;
+        UmCarouselItem *item;
+        GtkWidget *child;
+        gpointer uid;
 
-        tv = (GtkTreeView *)get_widget (d, "list-treeview");
-        model = gtk_tree_view_get_model (tv);
-        selection = gtk_tree_view_get_selection (tv);
+        item = um_carousel_find_item (d->carousel, user, user_compare);
+        if (item == NULL)
+                return;
 
-        g_assert (gtk_tree_model_get_iter_first (model, &iter));
-        do {
-                gtk_tree_model_get (model, &iter, USER_COL, &current, -1);
-                if (current == user) {
-                        text = get_name_col_str (user);
+        child = gtk_bin_get_child (GTK_BIN (item));
+        gtk_widget_destroy (child);
 
-                        gtk_list_store_set (GTK_LIST_STORE (model), &iter,
-                                            USER_COL, user,
-                                            NAME_COL, text,
-                                            -1);
-                        g_free (text);
-                        g_object_unref (current);
+        child = create_carousel_entry (d, user);
+        gtk_container_add (GTK_CONTAINER (item), child);
 
-                        break;
-                }
-                if (current)
-                        g_object_unref (current);
+        uid = GINT_TO_POINTER (act_user_get_uid (user));
+        g_object_set_data (G_OBJECT (item), "uid", uid);
 
-        } while (gtk_tree_model_iter_next (model, &iter));
+        gtk_widget_show_all (child);
 
-        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
-                gtk_tree_model_get (model, &iter, USER_COL, &current, -1);
-
-                if (current == user) {
-                        show_user (user, d);
-                }
-                if (current)
-                        g_object_unref (current);
-        }
 }
 
 static void
@@ -383,14 +336,8 @@ select_created_user (GObject *object,
 {
         CcUserPanelPrivate *d = user_data;
         UmAccountDialog *dialog;
-        GtkTreeView *tv;
-        GtkTreeModel *model;
-        GtkTreeSelection *selection;
-        GtkTreeIter iter;
-        ActUser *current;
-        GtkTreePath *path;
+        UmCarouselItem *item;
         ActUser *user;
-        uid_t user_uid;
 
         dialog = UM_ACCOUNT_DIALOG (object);
         user = um_account_dialog_finish (dialog, result);
@@ -400,28 +347,11 @@ select_created_user (GObject *object,
         if (user == NULL)
                 return;
 
-        tv = (GtkTreeView *)get_widget (d, "list-treeview");
-        model = gtk_tree_view_get_model (tv);
-        selection = gtk_tree_view_get_selection (tv);
-        user_uid = act_user_get_uid (user);
-
-        g_assert (gtk_tree_model_get_iter_first (model, &iter));
-        do {
-                gtk_tree_model_get (model, &iter, USER_COL, &current, -1);
-                if (current) {
-                        if (user_uid == act_user_get_uid (current)) {
-                                path = gtk_tree_model_get_path (model, &iter);
-                                gtk_tree_view_scroll_to_cell (tv, path, NULL, FALSE, 0.0, 0.0);
-                                gtk_tree_selection_select_path (selection, path);
-                                gtk_tree_path_free (path);
-                                g_object_unref (current);
-                                break;
-                        }
-                        g_object_unref (current);
-                }
-        } while (gtk_tree_model_iter_next (model, &iter));
+        reload_users (d);
 
-        g_object_unref (user);
+        /* Find and select the last created user */
+        item = um_carousel_find_item (d->carousel, user, user_compare);
+        um_carousel_select_item (d->carousel, item);
 }
 
 static void
@@ -482,8 +412,6 @@ delete_user_response (GtkWidget         *dialog,
                                             NULL,
                                             (GAsyncReadyCallback)delete_user_done,
                                             d);
-
-        g_object_unref (user);
 }
 
 static void
@@ -643,8 +571,6 @@ delete_enterprise_user_response (GtkWidget          *dialog,
         data->cancellable = g_object_ref (d->cancellable);
         data->login = g_strdup (act_user_get_user_name (user));
 
-        g_object_unref (user);
-
         /* Uncache the user account from the accountsservice */
         g_debug ("Uncaching remote user: %s", data->login);
 
@@ -734,8 +660,6 @@ delete_user (GtkButton *button, CcUserPanel *self)
         gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
 
         gtk_window_present (GTK_WINDOW (dialog));
-
-        g_object_unref (user);
 }
 
 static const gchar *
@@ -817,8 +741,6 @@ autologin_changed (GObject            *object,
                         g_slist_free (list);
                 }
         }
-
-        g_object_unref (user);
 }
 
 static gchar *
@@ -878,6 +800,8 @@ show_user (ActUser *user, CcUserPanelPrivate *d)
         gboolean show, enable;
         ActUser *current;
 
+        d->selected_user = user;
+
         image = get_widget (d, "user-icon-image");
         um_user_image_set_user (UM_USER_IMAGE (image), user);
         image = get_widget (d, "user-icon-image2");
@@ -976,23 +900,6 @@ show_user (ActUser *user, CcUserPanelPrivate *d)
 }
 
 static void
-selected_user_changed (GtkTreeSelection *selection, CcUserPanelPrivate *d)
-{
-        GtkTreeModel *model;
-        GtkTreeIter iter;
-        ActUser *user;
-
-        if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
-                gtk_tree_model_get (model, &iter, USER_COL, &user, -1);
-                show_user (user, d);
-                gtk_widget_set_sensitive (get_widget (d, "main-user-vbox"), TRUE);
-                g_object_unref (user);
-        } else {
-                gtk_widget_set_sensitive (get_widget (d, "main-user-vbox"), FALSE);
-        }
-}
-
-static void
 change_name_done (GtkWidget          *entry,
                   CcUserPanelPrivate *d)
 {
@@ -1006,8 +913,6 @@ change_name_done (GtkWidget          *entry,
             is_valid_name (text)) {
                 act_user_set_real_name (user, text);
         }
-
-        g_object_unref (user);
 }
 
 static void
@@ -1037,8 +942,6 @@ account_type_changed (GtkToggleButton    *button,
                 if (self_selected)
                         show_restart_notification (d, NULL);
         }
-
-        g_object_unref (user);
 }
 
 static void
@@ -1114,8 +1017,6 @@ language_response (GtkDialog         *dialog,
                 g_free (name);
         }
 
-        g_object_unref (user);
-
         gtk_widget_hide (GTK_WIDGET (dialog));
 }
 
@@ -1147,8 +1048,6 @@ change_language (GtkButton *button,
         if (current_language && *current_language != '\0')
                 cc_language_chooser_set_language (d->language_chooser, current_language);
         gtk_window_present (GTK_WINDOW (d->language_chooser));
-
-        g_object_unref (user);
 }
 
 static void
@@ -1161,8 +1060,6 @@ change_password (GtkButton *button, CcUserPanelPrivate *d)
         um_password_dialog_set_user (d->password_dialog, user);
         um_password_dialog_show (d->password_dialog,
                                   GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)));
-
-        g_object_unref (user);
 }
 
 static void
@@ -1177,8 +1074,6 @@ change_fingerprint (GtkButton *button, CcUserPanelPrivate *d)
 
         widget = get_widget (d, "account-fingerprint-button");
         fingerprint_button_clicked (GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)), widget, user);
-
-        g_object_unref (user);
 }
 
 static void
@@ -1190,57 +1085,6 @@ show_history (GtkButton *button, CcUserPanelPrivate *d)
 
         um_history_dialog_set_user (d->history_dialog, user);
         um_history_dialog_show (d->history_dialog, GTK_WINDOW (gtk_widget_get_toplevel (d->main_box)));
-
-        g_object_unref (user);
-}
-
-static gint
-sort_users (GtkTreeModel *model,
-            GtkTreeIter  *a,
-            GtkTreeIter  *b,
-            gpointer      data)
-{
-        ActUser *ua, *ub;
-        gint sa, sb;
-        gint result;
-
-        gtk_tree_model_get (model, a, USER_COL, &ua, SORT_KEY_COL, &sa, -1);
-        gtk_tree_model_get (model, b, USER_COL, &ub, SORT_KEY_COL, &sb, -1);
-
-        if (sa < sb) {
-                result = -1;
-        }
-        else if (sa > sb) {
-                result = 1;
-        }
-        else {
-                result = act_user_collate (ua, ub);
-        }
-
-        if (ua) {
-                g_object_unref (ua);
-        }
-        if (ub) {
-                g_object_unref (ub);
-        }
-
-        return result;
-}
-
-static gboolean
-dont_select_headings (GtkTreeSelection *selection,
-                      GtkTreeModel     *model,
-                      GtkTreePath      *path,
-                      gboolean          selected,
-                      gpointer          data)
-{
-        GtkTreeIter iter;
-        gboolean is_user;
-
-        gtk_tree_model_get_iter (model, &iter, path);
-        gtk_tree_model_get (model, &iter, USER_ROW_COL, &is_user, -1);
-
-        return is_user;
 }
 
 static void
@@ -1248,7 +1092,6 @@ users_loaded (ActUserManager     *manager,
               GParamSpec         *pspec,
               CcUserPanelPrivate *d)
 {
-        GSList *list, *l;
         ActUser *user;
         GtkWidget *dialog;
 
@@ -1268,22 +1111,16 @@ users_loaded (ActUserManager     *manager,
                 gtk_widget_set_sensitive (d->main_box, FALSE);
         }
 
-        list = act_user_manager_list_users (d->um);
-        g_debug ("Got %d users\n", g_slist_length (list));
-
         g_signal_connect (d->um, "user-changed", G_CALLBACK (user_changed), d);
         g_signal_connect (d->um, "user-is-logged-in-changed", G_CALLBACK (user_changed), d);
-
-        for (l = list; l; l = l->next) {
-                user = l->data;
-                g_debug ("adding user %s\n", get_real_or_user_name (user));
-                user_added (d->um, user, d);
-        }
-        show_user (list->data, d);
-        g_slist_free (list);
-
         g_signal_connect (d->um, "user-added", G_CALLBACK (user_added), d);
         g_signal_connect (d->um, "user-removed", G_CALLBACK (user_removed), d);
+
+        reload_users (d);
+
+        /* Show the current user firstly. */
+        user = act_user_manager_get_user_by_id (d->um, getuid ());
+        show_user (user, d);
 }
 
 static void
@@ -1454,88 +1291,13 @@ on_permission_changed (GPermission *permission,
         }
 
         um_password_dialog_set_user (d->password_dialog, user);
-
-        g_object_unref (user);
-}
-
-static gboolean
-match_user (GtkTreeModel *model,
-            gint          column,
-            const gchar  *key,
-            GtkTreeIter  *iter,
-            gpointer      search_data)
-{
-        ActUser *user;
-        const gchar *name;
-        gchar *normalized_key = NULL;
-        gchar *normalized_name = NULL;
-        gchar *case_normalized_key = NULL;
-        gchar *case_normalized_name = NULL;
-        gchar *p;
-        gboolean result = TRUE;
-        gint i;
-
-        gtk_tree_model_get (model, iter, USER_COL, &user, -1);
-
-        if (!user) {
-                goto out;
-        }
-
-        normalized_key = g_utf8_normalize (key, -1, G_NORMALIZE_ALL);
-        if (!normalized_key) {
-                goto out;
-        }
-
-        case_normalized_key = g_utf8_casefold (normalized_key, -1);
-
-        for (i = 0; i < 2; i++) {
-                if (i == 0) {
-                        name = act_user_get_real_name (user);
-                }
-                else {
-                        name = act_user_get_user_name (user);
-                }
-                g_free (normalized_name);
-                normalized_name = g_utf8_normalize (name, -1, G_NORMALIZE_ALL);
-                if (normalized_name) {
-                        g_free (case_normalized_name);
-                        case_normalized_name = g_utf8_casefold (normalized_name, -1);
-                        p = strstr (case_normalized_name, case_normalized_key);
-
-                        /* poor man's \b */
-                        if (p == case_normalized_name || (p && p[-1] == ' ')) {
-                                result = FALSE;
-                                break;
-                        }
-                }
-        }
-
- out:
-        if (user) {
-                g_object_unref (user);
-        }
-        g_free (normalized_key);
-        g_free (case_normalized_key);
-        g_free (normalized_name);
-        g_free (case_normalized_name);
-
-        return result;
 }
 
 static void
 setup_main_window (CcUserPanel *self)
 {
         CcUserPanelPrivate *d = self->priv;
-        GtkWidget *userlist;
-        GtkTreeModel *model;
-        GtkListStore *store;
-        GtkTreeViewColumn *column;
-        GtkCellRenderer *cell;
-        GtkTreeSelection *selection;
         GtkWidget *button;
-        GtkTreeIter iter;
-        gint expander_size;
-        gchar *title;
         GIcon *icon;
         GError *error = NULL;
         gchar *names[3];
@@ -1549,62 +1311,10 @@ setup_main_window (CcUserPanel *self)
         button = get_widget (d, "dismiss-button");
         g_signal_connect_swapped (button, "clicked", G_CALLBACK (dismiss_notification), d);
 
-        userlist = get_widget (d, "list-treeview");
-        store = gtk_list_store_new (NUM_USER_LIST_COLS,
-                                    ACT_TYPE_USER,
-                                    G_TYPE_STRING,
-                                    G_TYPE_BOOLEAN,
-                                    G_TYPE_STRING,
-                                    G_TYPE_BOOLEAN,
-                                    G_TYPE_INT);
-        model = (GtkTreeModel *)store;
-        gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model), sort_users, NULL, NULL);
-        gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), 
GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
-        gtk_tree_view_set_model (GTK_TREE_VIEW (userlist), model);
-        gtk_tree_view_set_search_column (GTK_TREE_VIEW (userlist), USER_COL);
-        gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (userlist),
-                                             match_user, NULL, NULL);
-        g_object_unref (model);
-
-        gtk_widget_style_get (userlist, "expander-size", &expander_size, NULL);
-        gtk_tree_view_set_level_indentation (GTK_TREE_VIEW (userlist), - (expander_size + 6));
-
-        title = g_strdup_printf ("<small><span foreground=\"#555555\">%s</span></small>", _("My Account"));
-        gtk_list_store_append (store, &iter);
-        gtk_list_store_set (store, &iter,
-                            TITLE_COL, title,
-                            HEADING_ROW_COL, TRUE,
-                            SORT_KEY_COL, 0,
-                            -1);
-        g_free (title);
-
         d->other_accounts = 0;
-        d->other_iter = NULL;
-
-        column = gtk_tree_view_column_new ();
-        cell = um_cell_renderer_user_image_new (userlist);
-        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, FALSE);
-        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "user", USER_COL);
-        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", USER_ROW_COL);
-        cell = gtk_cell_renderer_text_new ();
-        g_object_set (cell, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, TRUE);
-        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "markup", NAME_COL);
-        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", USER_ROW_COL);
-        cell = gtk_cell_renderer_text_new ();
-        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), cell, TRUE);
-        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "markup", TITLE_COL);
-        gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (column), cell, "visible", HEADING_ROW_COL);
-
-        gtk_tree_view_append_column (GTK_TREE_VIEW (userlist), column);
-
-        selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (userlist));
-        gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
-        g_signal_connect (selection, "changed", G_CALLBACK (selected_user_changed), d);
-        gtk_tree_selection_set_select_function (selection, dont_select_headings, NULL, NULL);
-
-        gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (get_widget (d, 
"list-scrolledwindow")), 300);
-        gtk_widget_set_size_request (get_widget (d, "list-scrolledwindow"), 200, -1);
+
+        d->carousel = UM_CAROUSEL (get_widget (d, "carousel"));
+        g_signal_connect (d->carousel, "item-activated", G_CALLBACK (set_selected_user), d);
 
         button = get_widget (d, "add-user-toolbutton");
         g_signal_connect (button, "clicked", G_CALLBACK (add_user), d);
@@ -1727,6 +1437,7 @@ cc_user_panel_init (CcUserPanel *self)
         /* register types that the builder might need */
         type = um_user_image_get_type ();
         type = um_cell_renderer_user_image_get_type ();
+        type = um_carousel_get_type ();
 
         gtk_widget_set_size_request (GTK_WIDGET (self), -1, 350);
 
@@ -1797,10 +1508,6 @@ cc_user_panel_dispose (GObject *object)
                 g_object_unref (priv->permission);
                 priv->permission = NULL;
         }
-        if (priv->other_iter) {
-                gtk_tree_iter_free (priv->other_iter);
-                priv->other_iter = NULL;
-        }
         G_OBJECT_CLASS (cc_user_panel_parent_class)->dispose (object);
 }
 
diff --git a/panels/user-accounts/user-accounts.gresource.xml 
b/panels/user-accounts/user-accounts.gresource.xml
index ad57a8a..4bedc2d 100644
--- a/panels/user-accounts/user-accounts.gresource.xml
+++ b/panels/user-accounts/user-accounts.gresource.xml
@@ -7,6 +7,7 @@
     <file alias="password-dialog.ui" preprocess="xml-stripblanks">data/password-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="carousel.ui" preprocess="xml-stripblanks">data/carousel.ui</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]