[libadwaita/wip/exalm/demo-cleanups: 10/21] demo: Split avatar page into a separate class




commit 9972f8c6a396a7b2bef1de5a478dfd94185ec1db
Author: Alexander Mikhaylenko <alexm gnome org>
Date:   Thu Dec 9 17:51:01 2021 +0500

    demo: Split avatar page into a separate class

 demo/adw-demo-window.c                    | 201 +----------------------------
 demo/adw-demo-window.ui                   | 182 +-------------------------
 demo/adwaita-demo.gresources.xml          |   1 +
 demo/meson.build                          |   1 +
 demo/pages/avatar/adw-demo-page-avatar.c  | 204 ++++++++++++++++++++++++++++++
 demo/pages/avatar/adw-demo-page-avatar.h  |  11 ++
 demo/pages/avatar/adw-demo-page-avatar.ui | 182 ++++++++++++++++++++++++++
 7 files changed, 402 insertions(+), 380 deletions(-)
---
diff --git a/demo/adw-demo-window.c b/demo/adw-demo-window.c
index 6d7e2ce4..853ef285 100644
--- a/demo/adw-demo-window.c
+++ b/demo/adw-demo-window.c
@@ -1,6 +1,7 @@
 #include "adw-demo-window.h"
 
 #include <glib/gi18n.h>
+#include "pages/avatar/adw-demo-page-avatar.h"
 #include "pages/carousel/adw-demo-page-carousel.h"
 #include "pages/clamp/adw-demo-page-clamp.h"
 #include "pages/leaflet/adw-demo-page-leaflet.h"
@@ -22,12 +23,6 @@ struct _AdwDemoWindow
   GtkStackSidebar *sidebar;
   GtkStack *stack;
   AdwLeaflet *subpage_leaflet;
-  AdwAvatar *avatar;
-  GtkEntry *avatar_text;
-  GtkLabel *avatar_file_chooser_label;
-  GtkButton *avatar_remove_button;
-  GtkFileChooserNative *avatar_file_chooser;
-  GtkListBox *avatar_contacts;
   int toast_undo_items;
   AdwToast *undo_toast;
   GtkStack *animation_preferences_stack;
@@ -167,165 +162,6 @@ adw_demo_window_new (GtkApplication *application)
   return g_object_new (ADW_TYPE_DEMO_WINDOW, "application", application, NULL);
 }
 
-static void
-avatar_file_remove_cb (AdwDemoWindow *self)
-{
-  g_assert (ADW_IS_DEMO_WINDOW (self));
-
-  g_signal_handlers_disconnect_by_data (self->avatar, self);
-
-  gtk_label_set_label (self->avatar_file_chooser_label, _("(None)"));
-  gtk_widget_set_sensitive (GTK_WIDGET (self->avatar_remove_button), FALSE);
-  adw_avatar_set_custom_image (self->avatar, NULL);
-}
-
-static void
-avatar_file_chooser_response_cb (AdwDemoWindow *self,
-                                 int            response)
-{
-  g_autoptr (GFile) file = NULL;
-  g_autoptr (GFileInfo) info = NULL;
-  g_autoptr (GdkTexture) texture = NULL;
-  g_autoptr (GError) error = NULL;
-
-  g_assert (ADW_IS_DEMO_WINDOW (self));
-
-  if (response != GTK_RESPONSE_ACCEPT)
-    return;
-
-  file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (self->avatar_file_chooser));
-  info = g_file_query_info (file,
-                            G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
-                            G_FILE_QUERY_INFO_NONE,
-                            NULL,
-                            NULL);
-
-  if (info)
-    gtk_label_set_label (self->avatar_file_chooser_label,
-                         g_file_info_get_display_name (info));
-
-  gtk_widget_set_sensitive (GTK_WIDGET (self->avatar_remove_button), TRUE);
-
-  texture = gdk_texture_new_from_file (file, &error);
-  if (error)
-    g_critical ("Failed to create texture from file: %s", error->message);
-
-  adw_avatar_set_custom_image (self->avatar, texture ? GDK_PAINTABLE (texture) : NULL);
-}
-
-static void
-avatar_file_chooser_clicked_cb (AdwDemoWindow *self)
-{
-  gtk_native_dialog_show (GTK_NATIVE_DIALOG (self->avatar_file_chooser));
-}
-
-static void
-file_chooser_response_cb (AdwDemoWindow  *self,
-                          int             response_id,
-                          GtkFileChooser *chooser)
-{
-  if (response_id == GTK_RESPONSE_ACCEPT) {
-    g_autoptr (GFile) file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (chooser));
-    g_autoptr (GdkTexture) texture =
-      adw_avatar_draw_to_texture (self->avatar,
-                                  gtk_widget_get_scale_factor (GTK_WIDGET (self)));
-
-    gdk_texture_save_to_png (texture, g_file_peek_path (file));
-  }
-
-  g_object_unref (chooser);
-}
-
-static void
-avatar_save_to_file_cb (AdwDemoWindow *self)
-{
-  GtkFileChooserNative *chooser = NULL;
-
-  g_assert (ADW_IS_DEMO_WINDOW (self));
-
-  chooser = gtk_file_chooser_native_new (_("Save Avatar"),
-                                         GTK_WINDOW (self),
-                                         GTK_FILE_CHOOSER_ACTION_SAVE,
-                                         _("_Save"),
-                                         _("_Cancel"));
-
-  g_signal_connect_swapped (chooser, "response", G_CALLBACK (file_chooser_response_cb), self);
-
-  gtk_native_dialog_show (GTK_NATIVE_DIALOG (chooser));
-}
-
-static char *
-avatar_new_random_name (void)
-{
-  static const char *first_names[] = {
-    "Adam",
-    "Adrian",
-    "Anna",
-    "Charlotte",
-    "Frédérique",
-    "Ilaria",
-    "Jakub",
-    "Jennyfer",
-    "Julia",
-    "Justin",
-    "Mario",
-    "Miriam",
-    "Mohamed",
-    "Nourimane",
-    "Owen",
-    "Peter",
-    "Petra",
-    "Rachid",
-    "Rebecca",
-    "Sarah",
-    "Thibault",
-    "Wolfgang",
-  };
-  static const char *last_names[] = {
-    "Bailey",
-    "Berat",
-    "Chen",
-    "Farquharson",
-    "Ferber",
-    "Franco",
-    "Galinier",
-    "Han",
-    "Lawrence",
-    "Lepied",
-    "Lopez",
-    "Mariotti",
-    "Rossi",
-    "Urasawa",
-    "Zwickelman",
-  };
-
-  return g_strdup_printf ("%s %s",
-                          first_names[g_random_int_range (0, G_N_ELEMENTS (first_names))],
-                          last_names[g_random_int_range (0, G_N_ELEMENTS (last_names))]);
-}
-
-static void
-avatar_update_contacts (AdwDemoWindow *self)
-{
-  GtkWidget *row;
-
-  while ((row = gtk_widget_get_first_child (GTK_WIDGET (self->avatar_contacts))))
-    gtk_list_box_remove (self->avatar_contacts, row);
-
-  for (int i = 0; i < 30; i++) {
-    g_autofree char *name = avatar_new_random_name ();
-    GtkWidget *contact = adw_action_row_new ();
-    GtkWidget *avatar = adw_avatar_new (40, name, TRUE);
-
-    gtk_widget_set_margin_top (avatar, 12);
-    gtk_widget_set_margin_bottom (avatar, 12);
-
-    adw_preferences_row_set_title (ADW_PREFERENCES_ROW (contact), name);
-    adw_action_row_add_prefix (ADW_ACTION_ROW (contact), avatar);
-    gtk_list_box_append (self->avatar_contacts, contact);
-  }
-}
-
 static void
 flap_demo_clicked_cb (GtkButton     *btn,
                       AdwDemoWindow *self)
@@ -676,11 +512,6 @@ adw_demo_window_class_init (AdwDemoWindowClass *klass)
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, sidebar);
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, stack);
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, subpage_leaflet);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, avatar);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, avatar_text);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, avatar_file_chooser_label);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, avatar_remove_button);
-  gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, avatar_contacts);
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, toast_overlay);
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, animation_preferences_stack);
   gtk_widget_class_bind_template_child (widget_class, AdwDemoWindow, timed_animation_sample);
@@ -702,9 +533,6 @@ adw_demo_window_class_init (AdwDemoWindowClass *klass)
   gtk_widget_class_bind_template_callback (widget_class, leaflet_next_page_cb);
   gtk_widget_class_bind_template_callback (widget_class, get_color_scheme_icon_name);
   gtk_widget_class_bind_template_callback (widget_class, color_scheme_button_clicked_cb);
-  gtk_widget_class_bind_template_callback (widget_class, avatar_file_remove_cb);
-  gtk_widget_class_bind_template_callback (widget_class, avatar_file_chooser_clicked_cb);
-  gtk_widget_class_bind_template_callback (widget_class, avatar_save_to_file_cb);
   gtk_widget_class_bind_template_callback (widget_class, flap_demo_clicked_cb);
   gtk_widget_class_bind_template_callback (widget_class, tab_view_demo_clicked_cb);
   gtk_widget_class_bind_template_callback (widget_class, style_classes_demo_clicked_cb);
@@ -737,30 +565,6 @@ adw_demo_window_class_init (AdwDemoWindowClass *klass)
   g_object_class_install_properties (object_class, LAST_PROP, props);
 }
 
-static void
-avatar_page_init (AdwDemoWindow *self)
-{
-  g_autofree char *name = avatar_new_random_name ();
-
-  gtk_editable_set_text (GTK_EDITABLE (self->avatar_text), name);
-
-  avatar_update_contacts (self);
-
-  self->avatar_file_chooser =
-    gtk_file_chooser_native_new (_("Select an Avatar"),
-                                 GTK_WINDOW (self),
-                                 GTK_FILE_CHOOSER_ACTION_OPEN,
-                                 _("_Select"),
-                                 _("_Cancel"));
-
-  gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (self->avatar_file_chooser), TRUE);
-  g_signal_connect_object (self->avatar_file_chooser, "response",
-                           G_CALLBACK (avatar_file_chooser_response_cb), self,
-                           G_CONNECT_SWAPPED);
-
-  avatar_file_remove_cb (self);
-}
-
 static void
 animation_page_init (AdwDemoWindow *self)
 {
@@ -828,6 +632,7 @@ adw_demo_window_init (AdwDemoWindow *self)
 {
   AdwStyleManager *manager = adw_style_manager_get_default ();
 
+  g_type_ensure (ADW_TYPE_DEMO_PAGE_AVATAR);
   g_type_ensure (ADW_TYPE_DEMO_PAGE_CAROUSEL);
   g_type_ensure (ADW_TYPE_DEMO_PAGE_CLAMP);
   g_type_ensure (ADW_TYPE_DEMO_PAGE_LEAFLET);
@@ -845,8 +650,6 @@ adw_demo_window_init (AdwDemoWindow *self)
 
   notify_system_supports_color_schemes_cb (self);
 
-  avatar_page_init (self);
-
   adw_leaflet_set_visible_child (self->content_box, GTK_WIDGET (self->right_box));
 
   gtk_widget_action_set_enabled (GTK_WIDGET (self), "toast.dismiss", FALSE);
diff --git a/demo/adw-demo-window.ui b/demo/adw-demo-window.ui
index 277b199b..0715b24a 100644
--- a/demo/adw-demo-window.ui
+++ b/demo/adw-demo-window.ui
@@ -173,174 +173,9 @@
                         </child>
                         <child>
                           <object class="GtkStackPage">
-                            <property name="name">avatar</property>
                             <property name="title" translatable="yes">Avatar</property>
                             <property name="child">
-                              <object class="GtkScrolledWindow">
-                                <property name="hscrollbar-policy">never</property>
-                                <property name="child">
-                                  <object class="GtkViewport">
-                                    <property name="scroll-to-focus">True</property>
-                                    <property name="child">
-                                      <object class="GtkBox">
-                                        <property name="orientation">vertical</property>
-                                        <property name="valign">start</property>
-                                        <style>
-                                          <class name="avatar-page"/>
-                                        </style>
-                                        <child>
-                                          <object class="GtkBox">
-                                            <property name="orientation">vertical</property>
-                                            <child>
-                                              <object class="AdwAvatar" id="avatar">
-                                                <property name="valign">center</property>
-                                                <property name="size" bind-source="avatar_size" 
bind-property="value" bind-flags="sync-create"></property>
-                                                <property name="show-initials" 
bind-source="avatar_show_initials" bind-property="state" bind-flags="sync-create"/>
-                                                <property name="text" bind-source="avatar_text" 
bind-property="text" bind-flags="sync-create"/>
-                                                <property name="margin-bottom">36</property>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="GtkLabel">
-                                                <property name="label" translatable="yes">Avatar</property>
-                                                <property name="wrap">True</property>
-                                                <property name="wrap-mode">word-char</property>
-                                                <property name="justify">center</property>
-                                                <style>
-                                                  <class name="title"/>
-                                                  <class name="title-1"/>
-                                                </style>
-                                              </object>
-                                            </child>
-                                            <child>
-                                              <object class="GtkLabel">
-                                                <property name="label" translatable="yes">A user avatar with 
generated fallback.</property>
-                                                <property name="justify">center</property>
-                                                <property name="use_markup">true</property>
-                                                <property name="wrap">True</property>
-                                                <style>
-                                                  <class name="body"/>
-                                                  <class name="description"/>
-                                                </style>
-                                              </object>
-                                            </child>
-                                          </object>
-                                        </child>
-                                        <child>
-                                          <object class="AdwClamp">
-                                            <property name="maximum-size">400</property>
-                                            <property name="tightening-threshold">300</property>
-                                            <property name="child">
-                                              <object class="GtkBox">
-                                                <property name="valign">center</property>
-                                                <property name="orientation">vertical</property>
-                                                <property name="spacing">12</property>
-                                                <child>
-                                                  <object class="AdwPreferencesGroup">
-                                                    <child>
-                                                      <object class="AdwActionRow">
-                                                        <property name="title" 
translatable="yes">Text</property>
-                                                        <child>
-                                                          <object class="GtkEntry" id="avatar_text">
-                                                            <property name="valign">center</property>
-                                                          </object>
-                                                        </child>
-                                                      </object>
-                                                    </child>
-                                                    <child>
-                                                      <object class="AdwActionRow">
-                                                        <property name="title" translatable="yes">Show 
Initials</property>
-                                                        <property 
name="activatable_widget">avatar_show_initials</property>
-                                                        <child>
-                                                          <object class="GtkSwitch" 
id="avatar_show_initials">
-                                                            <property name="valign">center</property>
-                                                            <property name="state">True</property>
-                                                          </object>
-                                                        </child>
-                                                      </object>
-                                                    </child>
-                                                    <child>
-                                                      <object class="AdwActionRow">
-                                                        <property name="title" 
translatable="yes">File</property>
-                                                        <child>
-                                                          <object class="GtkButton">
-                                                            <property name="valign">center</property>
-                                                            <signal name="clicked" 
handler="avatar_file_chooser_clicked_cb" swapped="true"/>
-                                                            <child>
-                                                              <object class="GtkBox">
-                                                                <property name="spacing">6</property>
-                                                                <child>
-                                                                  <object class="GtkImage">
-                                                                    <property 
name="icon-name">document-open-symbolic</property>
-                                                                  </object>
-                                                                </child>
-                                                                <child>
-                                                                  <object class="GtkLabel" 
id="avatar_file_chooser_label">
-                                                                    <property 
name="ellipsize">middle</property>
-                                                                  </object>
-                                                                </child>
-                                                              </object>
-                                                            </child>
-                                                          </object>
-                                                        </child>
-                                                        <child>
-                                                          <object class="GtkButton" 
id="avatar_remove_button">
-                                                            <property name="valign">center</property>
-                                                            <property 
name="icon_name">user-trash-symbolic</property>
-                                                            <signal name="clicked" swapped="yes" 
handler="avatar_file_remove_cb"/>
-                                                            <style>
-                                                              <class name="flat"/>
-                                                            </style>
-                                                          </object>
-                                                        </child>
-                                                      </object>
-                                                    </child>
-                                                    <child>
-                                                      <object class="AdwActionRow">
-                                                        <property name="title" 
translatable="yes">Size</property>
-                                                        <child>
-                                                          <object class="GtkSpinButton" id="avatar_size">
-                                                            <property name="valign">center</property>
-                                                            <property name="numeric">True</property>
-                                                            <property 
name="adjustment">avatar_adjustment</property>
-                                                          </object>
-                                                        </child>
-                                                      </object>
-                                                    </child>
-                                                    <child>
-                                                      <object class="AdwActionRow">
-                                                        <property name="title" translatable="yes">Export to 
File</property>
-                                                        <child>
-                                                          <object class="GtkButton" id="avatar_save_file">
-                                                            <property name="valign">center</property>
-                                                            <property 
name="icon_name">avatar-save-symbolic</property>
-                                                            <signal name="clicked" swapped="yes" 
handler="avatar_save_to_file_cb"/>
-                                                            <style>
-                                                              <class name="flat"/>
-                                                            </style>
-                                                          </object>
-                                                        </child>
-                                                      </object>
-                                                    </child>
-                                                  </object>
-                                                </child>
-                                                <child>
-                                                  <object class="GtkListBox" id="avatar_contacts">
-                                                    <property name="selection-mode">none</property>
-                                                    <style>
-                                                      <class name="boxed-list"/>
-                                                    </style>
-                                                  </object>
-                                                </child>
-                                              </object>
-                                            </property>
-                                          </object>
-                                        </child>
-                                      </object>
-                                    </property>
-                                  </object>
-                                </property>
-                              </object>
+                              <object class="AdwDemoPageAvatar"/>
                             </property>
                           </object>
                         </child>
@@ -1035,19 +870,4 @@
       </object>
     </child>
   </template>
-  <object class="GtkAdjustment" id="avatar_adjustment">
-    <property name="lower">24</property>
-    <property name="upper">320</property>
-    <property name="value">128</property>
-    <property name="page-increment">8</property>
-    <property name="step-increment">8</property>
-  </object>
-  <object class="GtkFileFilter" id="avatar_file_filter">
-    <mime-types>
-      <mime-type>image/png</mime-type>
-      <mime-type>image/jpeg</mime-type>
-      <mime-type>image/jpg</mime-type>
-      <mime-type>image/gif</mime-type>
-    </mime-types>
-  </object>
 </interface>
diff --git a/demo/adwaita-demo.gresources.xml b/demo/adwaita-demo.gresources.xml
index c9494954..178dbf5c 100644
--- a/demo/adwaita-demo.gresources.xml
+++ b/demo/adwaita-demo.gresources.xml
@@ -41,6 +41,7 @@
     <file compressed="true">style-dark.css</file>
   </gresource>
   <gresource prefix="/org/gnome/Adwaita1/Demo/ui">
+    <file preprocess="xml-stripblanks">pages/avatar/adw-demo-page-avatar.ui</file>
     <file preprocess="xml-stripblanks">pages/carousel/adw-demo-page-carousel.ui</file>
     <file preprocess="xml-stripblanks">pages/clamp/adw-demo-page-clamp.ui</file>
     <file preprocess="xml-stripblanks">pages/leaflet/adw-demo-page-leaflet.ui</file>
diff --git a/demo/meson.build b/demo/meson.build
index 7347336d..4c8b7e56 100644
--- a/demo/meson.build
+++ b/demo/meson.build
@@ -12,6 +12,7 @@ adwaita_demo_resources = gnome.compile_resources(
 adwaita_demo_sources = [
   adwaita_demo_resources,
 
+  'pages/avatar/adw-demo-page-avatar.c',
   'pages/carousel/adw-demo-page-carousel.c',
   'pages/clamp/adw-demo-page-clamp.c',
   'pages/leaflet/adw-demo-page-leaflet.c',
diff --git a/demo/pages/avatar/adw-demo-page-avatar.c b/demo/pages/avatar/adw-demo-page-avatar.c
new file mode 100644
index 00000000..05ad55c6
--- /dev/null
+++ b/demo/pages/avatar/adw-demo-page-avatar.c
@@ -0,0 +1,204 @@
+#include "adw-demo-page-avatar.h"
+
+#include <glib/gi18n.h>
+
+struct _AdwDemoPageAvatar
+{
+  AdwBin parent_instance;
+
+  AdwAvatar *avatar;
+  GtkEntry *text;
+  GtkLabel *file_chooser_label;
+  GtkListBox *contacts;
+};
+
+G_DEFINE_TYPE (AdwDemoPageAvatar, adw_demo_page_avatar, ADW_TYPE_BIN)
+
+static char *
+create_random_name (void)
+{
+  static const char *first_names[] = {
+    "Adam",
+    "Adrian",
+    "Anna",
+    "Charlotte",
+    "Frédérique",
+    "Ilaria",
+    "Jakub",
+    "Jennyfer",
+    "Julia",
+    "Justin",
+    "Mario",
+    "Miriam",
+    "Mohamed",
+    "Nourimane",
+    "Owen",
+    "Peter",
+    "Petra",
+    "Rachid",
+    "Rebecca",
+    "Sarah",
+    "Thibault",
+    "Wolfgang",
+  };
+  static const char *last_names[] = {
+    "Bailey",
+    "Berat",
+    "Chen",
+    "Farquharson",
+    "Ferber",
+    "Franco",
+    "Galinier",
+    "Han",
+    "Lawrence",
+    "Lepied",
+    "Lopez",
+    "Mariotti",
+    "Rossi",
+    "Urasawa",
+    "Zwickelman",
+  };
+
+  return g_strdup_printf ("%s %s",
+                          first_names[g_random_int_range (0, G_N_ELEMENTS (first_names))],
+                          last_names[g_random_int_range (0, G_N_ELEMENTS (last_names))]);
+}
+
+static void
+populate_contacts (AdwDemoPageAvatar *self)
+{
+  for (int i = 0; i < 30; i++) {
+    g_autofree char *name = create_random_name ();
+    GtkWidget *contact = adw_action_row_new ();
+    GtkWidget *avatar = adw_avatar_new (40, name, TRUE);
+
+    gtk_widget_set_margin_top (avatar, 12);
+    gtk_widget_set_margin_bottom (avatar, 12);
+
+    adw_preferences_row_set_title (ADW_PREFERENCES_ROW (contact), name);
+    adw_action_row_add_prefix (ADW_ACTION_ROW (contact), avatar);
+    gtk_list_box_append (self->contacts, contact);
+  }
+}
+
+static void
+open_response_cb (AdwDemoPageAvatar *self,
+                  GtkResponseType    response,
+                  GtkFileChooser    *chooser)
+{
+  if (response == GTK_RESPONSE_ACCEPT) {
+    g_autoptr (GFile) file = gtk_file_chooser_get_file (chooser);
+    g_autoptr (GFileInfo) info = NULL;
+    g_autoptr (GdkTexture) texture = NULL;
+    g_autoptr (GError) error = NULL;
+
+    info = g_file_query_info (file,
+                              G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
+                              G_FILE_QUERY_INFO_NONE,
+                              NULL,
+                              NULL);
+
+    if (info)
+      gtk_label_set_label (self->file_chooser_label,
+                           g_file_info_get_display_name (info));
+
+    gtk_widget_action_set_enabled (GTK_WIDGET (self), "avatar.remove", TRUE);
+
+    texture = gdk_texture_new_from_file (file, &error);
+    if (error)
+      g_critical ("Failed to create texture from file: %s", error->message);
+
+    adw_avatar_set_custom_image (self->avatar, texture ? GDK_PAINTABLE (texture) : NULL);
+  }
+
+  gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (chooser));
+}
+
+static void
+avatar_open_cb (AdwDemoPageAvatar *self)
+{
+  GtkRoot *root = gtk_widget_get_root (GTK_WIDGET (self));
+  GtkFileChooserNative *chooser =
+    gtk_file_chooser_native_new (_("Select an Avatar"),
+                                 GTK_WINDOW (root),
+                                 GTK_FILE_CHOOSER_ACTION_OPEN,
+                                 _("_Select"),
+                                 _("_Cancel"));
+  gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (chooser), TRUE);
+
+  g_signal_connect_swapped (chooser, "response", G_CALLBACK (open_response_cb), self);
+
+  gtk_native_dialog_show (GTK_NATIVE_DIALOG (chooser));
+}
+
+static void
+avatar_remove_cb (AdwDemoPageAvatar *self)
+{
+  gtk_label_set_label (self->file_chooser_label, _("(None)"));
+  gtk_widget_action_set_enabled (GTK_WIDGET (self), "avatar.remove", FALSE);
+  adw_avatar_set_custom_image (self->avatar, NULL);
+}
+
+static void
+save_response_cb (AdwDemoPageAvatar *self,
+                  GtkResponseType    response,
+                  GtkFileChooser    *chooser)
+{
+  if (response == GTK_RESPONSE_ACCEPT) {
+    g_autoptr (GFile) file = gtk_file_chooser_get_file (chooser);
+    g_autoptr (GdkTexture) texture =
+      adw_avatar_draw_to_texture (self->avatar,
+                                  gtk_widget_get_scale_factor (GTK_WIDGET (self)));
+
+    gdk_texture_save_to_png (texture, g_file_peek_path (file));
+  }
+
+  gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (chooser));
+}
+
+static void
+avatar_save_cb (AdwDemoPageAvatar *self)
+{
+  GtkRoot *root = gtk_widget_get_root (GTK_WIDGET (self));
+  GtkFileChooserNative *chooser =
+    gtk_file_chooser_native_new (_("Save Avatar"),
+                                 GTK_WINDOW (root),
+                                 GTK_FILE_CHOOSER_ACTION_SAVE,
+                                 _("_Save"),
+                                 _("_Cancel"));
+  gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (chooser), TRUE);
+
+  g_signal_connect_swapped (chooser, "response", G_CALLBACK (save_response_cb), self);
+
+  gtk_native_dialog_show (GTK_NATIVE_DIALOG (chooser));
+}
+
+static void
+adw_demo_page_avatar_class_init (AdwDemoPageAvatarClass *klass)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+  gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/Adwaita1/Demo/ui/pages/avatar/adw-demo-page-avatar.ui");
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAvatar, avatar);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAvatar, text);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAvatar, file_chooser_label);
+  gtk_widget_class_bind_template_child (widget_class, AdwDemoPageAvatar, contacts);
+
+  gtk_widget_class_install_action (widget_class, "avatar.open", NULL, (GtkWidgetActionActivateFunc) 
avatar_open_cb);
+  gtk_widget_class_install_action (widget_class, "avatar.remove", NULL, (GtkWidgetActionActivateFunc) 
avatar_remove_cb);
+  gtk_widget_class_install_action (widget_class, "avatar.save", NULL, (GtkWidgetActionActivateFunc) 
avatar_save_cb);
+}
+
+static void
+adw_demo_page_avatar_init (AdwDemoPageAvatar *self)
+{
+  g_autofree char *name = NULL;
+
+  gtk_widget_init_template (GTK_WIDGET (self));
+
+  name = create_random_name ();
+  gtk_editable_set_text (GTK_EDITABLE (self->text), name);
+
+  populate_contacts (self);
+  avatar_remove_cb (self);
+}
diff --git a/demo/pages/avatar/adw-demo-page-avatar.h b/demo/pages/avatar/adw-demo-page-avatar.h
new file mode 100644
index 00000000..972b8e86
--- /dev/null
+++ b/demo/pages/avatar/adw-demo-page-avatar.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <adwaita.h>
+
+G_BEGIN_DECLS
+
+#define ADW_TYPE_DEMO_PAGE_AVATAR (adw_demo_page_avatar_get_type())
+
+G_DECLARE_FINAL_TYPE (AdwDemoPageAvatar, adw_demo_page_avatar, ADW, DEMO_PAGE_AVATAR, AdwBin)
+
+G_END_DECLS
diff --git a/demo/pages/avatar/adw-demo-page-avatar.ui b/demo/pages/avatar/adw-demo-page-avatar.ui
new file mode 100644
index 00000000..b3acea24
--- /dev/null
+++ b/demo/pages/avatar/adw-demo-page-avatar.ui
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk" version="4.0"/>
+  <requires lib="libadwaita" version="1.0"/>
+  <template class="AdwDemoPageAvatar" parent="AdwBin">
+    <property name="child">
+      <object class="GtkScrolledWindow">
+        <property name="hscrollbar-policy">never</property>
+        <property name="child">
+          <object class="GtkViewport">
+            <property name="scroll-to-focus">True</property>
+            <property name="child">
+              <object class="GtkBox">
+                <property name="orientation">vertical</property>
+                <property name="valign">start</property>
+                <style>
+                  <class name="avatar-page"/>
+                </style>
+                <child>
+                  <object class="GtkBox">
+                    <property name="orientation">vertical</property>
+                    <child>
+                      <object class="AdwAvatar" id="avatar">
+                        <property name="valign">center</property>
+                        <property name="size" bind-source="size" bind-property="value" 
bind-flags="sync-create"></property>
+                        <property name="show-initials" bind-source="show_initials" bind-property="state" 
bind-flags="sync-create"/>
+                        <property name="text" bind-source="text" bind-property="text" 
bind-flags="sync-create"/>
+                        <property name="margin-bottom">36</property>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="label" translatable="yes">Avatar</property>
+                        <property name="wrap">True</property>
+                        <property name="wrap-mode">word-char</property>
+                        <property name="justify">center</property>
+                        <style>
+                          <class name="title"/>
+                          <class name="title-1"/>
+                        </style>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkLabel">
+                        <property name="label" translatable="yes">A user avatar with generated 
fallback.</property>
+                        <property name="justify">center</property>
+                        <property name="use-markup">true</property>
+                        <property name="wrap">True</property>
+                        <style>
+                          <class name="body"/>
+                          <class name="description"/>
+                        </style>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="AdwClamp">
+                    <property name="maximum-size">400</property>
+                    <property name="tightening-threshold">300</property>
+                    <property name="child">
+                      <object class="GtkBox">
+                        <property name="valign">center</property>
+                        <property name="orientation">vertical</property>
+                        <property name="spacing">12</property>
+                        <child>
+                          <object class="AdwPreferencesGroup">
+                            <child>
+                              <object class="AdwActionRow">
+                                <property name="title" translatable="yes">Text</property>
+                                <child>
+                                  <object class="GtkEntry" id="text">
+                                    <property name="valign">center</property>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="AdwActionRow">
+                                <property name="title" translatable="yes">Show Initials</property>
+                                <property name="activatable-widget">show_initials</property>
+                                <child>
+                                  <object class="GtkSwitch" id="show_initials">
+                                    <property name="valign">center</property>
+                                    <property name="state">True</property>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="AdwActionRow">
+                                <property name="title" translatable="yes">File</property>
+                                <child>
+                                  <object class="GtkButton">
+                                    <property name="valign">center</property>
+                                    <property name="action-name">avatar.open</property>
+                                    <child>
+                                      <object class="GtkBox">
+                                        <property name="spacing">6</property>
+                                        <child>
+                                          <object class="GtkImage">
+                                            <property name="icon-name">document-open-symbolic</property>
+                                          </object>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="file_chooser_label">
+                                            <property name="ellipsize">middle</property>
+                                          </object>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                </child>
+                                <child>
+                                  <object class="GtkButton">
+                                    <property name="valign">center</property>
+                                    <property name="icon-name">user-trash-symbolic</property>
+                                    <property name="action-name">avatar.remove</property>
+                                    <style>
+                                      <class name="flat"/>
+                                    </style>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="AdwActionRow">
+                                <property name="title" translatable="yes">Size</property>
+                                <child>
+                                  <object class="GtkSpinButton" id="size">
+                                    <property name="valign">center</property>
+                                    <property name="numeric">True</property>
+                                    <property name="adjustment">
+                                      <object class="GtkAdjustment">
+                                        <property name="lower">24</property>
+                                        <property name="upper">320</property>
+                                        <property name="value">128</property>
+                                        <property name="page-increment">8</property>
+                                        <property name="step-increment">8</property>
+                                      </object>
+                                    </property>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="AdwActionRow">
+                                <property name="title" translatable="yes">Export to File</property>
+                                <child>
+                                  <object class="GtkButton">
+                                    <property name="valign">center</property>
+                                    <property name="icon-name">avatar-save-symbolic</property>
+                                    <property name="action-name">avatar.save</property>
+                                    <style>
+                                      <class name="flat"/>
+                                    </style>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                        <child>
+                          <object class="GtkListBox" id="contacts">
+                            <property name="selection-mode">none</property>
+                            <style>
+                              <class name="boxed-list"/>
+                            </style>
+                          </object>
+                        </child>
+                      </object>
+                    </property>
+                  </object>
+                </child>
+              </object>
+            </property>
+          </object>
+        </property>
+      </object>
+    </property>
+  </template>
+</interface>


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