[gnome-contacts] avatar-selector: move selector to a dialog
- From: Niels De Graef <nielsdg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-contacts] avatar-selector: move selector to a dialog
- Date: Mon, 1 Feb 2021 11:44:13 +0000 (UTC)
commit f5cd13885851ed272ed88f03ddc5bc4df7673061
Author: Julian Sparber <julian sparber net>
Date: Thu Dec 17 13:37:00 2020 +0100
avatar-selector: move selector to a dialog
The previously used popover was to big and causes issues on
small screens and on X11.
This also merges the two FlowBoxes into one.
data/ui/contacts-avatar-selector.ui | 120 ++++++++++++++++++----------
data/ui/style.css | 5 ++
src/contacts-avatar-selector.vala | 155 +++++++++++++++++++++---------------
src/contacts-contact-editor.vala | 2 +-
4 files changed, 173 insertions(+), 109 deletions(-)
---
diff --git a/data/ui/contacts-avatar-selector.ui b/data/ui/contacts-avatar-selector.ui
index 895805a9..336b6baf 100644
--- a/data/ui/contacts-avatar-selector.ui
+++ b/data/ui/contacts-avatar-selector.ui
@@ -1,54 +1,102 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.22"/>
- <template class="ContactsAvatarSelector" parent="GtkPopover">
+ <template class="ContactsAvatarSelector" parent="GtkWindow">
<property name="can_focus">False</property>
- <child>
- <object class="GtkBox">
+ <property name="modal">True</property>
+ <property name="default_width">400</property>
+ <property name="default_height">400</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="skip_taskbar_hint">True</property>
+ <signal name="delete-event" handler="on_delete_event" swapped="no"/>
+ <child type="titlebar">
+ <object class="GtkHeaderBar">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="margin_left">10</property>
- <property name="margin_right">10</property>
- <property name="margin_top">10</property>
- <property name="margin_bottom">10</property>
- <property name="orientation">vertical</property>
- <property name="spacing">10</property>
+ <property name="can_focus">False</property>
<child>
- <object class="GtkFlowBox" id="personas_thumbnail_grid">
+ <object class="GtkButton">
+ <property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="column_spacing">5</property>
- <property name="row_spacing">5</property>
- <property name="selection_mode">none</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="on_cancel_clicked" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="label" translatable="yes">Done</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="on_done_clicked" swapped="no"/>
+ <style>
+ <class name="suggested-action"/>
+ </style>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
+ <property name="pack_type">end</property>
</packing>
</child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkFlowBox" id="stock_thumbnail_grid">
+ <object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="column_spacing">5</property>
- <property name="row_spacing">5</property>
- <property name="min_children_per_line">5</property>
- <property name="max_children_per_line">8</property>
- <property name="selection_mode">none</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">10</property>
+ <property name="margin_right">10</property>
+ <property name="margin_top">10</property>
+ <property name="margin_bottom">10</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkFlowBox" id="thumbnail_grid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="column_spacing">5</property>
+ <property name="row_spacing">5</property>
+ <property name="max_children_per_line">8</property>
+ <property name="selection_mode">single</property>
+ <property name="homogeneous">False</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
</object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator">
+ <property name="visible">True</property>
+ </object>>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">center</property>
+ <property name="margin_left">10</property>
+ <property name="margin_right">10</property>
+ <property name="margin_top">10</property>
+ <property name="margin_bottom">10</property>
<property name="spacing">10</property>
+ <property name="halign">center</property>
<child>
<object class="GtkButton" id="cheese_button">
<property name="label" translatable="yes">Take a Picture…</property>
@@ -57,11 +105,6 @@
<property name="receives_default">True</property>
<signal name="clicked" handler="on_cheese_clicked" swapped="no"/>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
</child>
<child>
<object class="GtkButton">
@@ -71,17 +114,10 @@
<property name="receives_default">True</property>
<signal name="clicked" handler="on_file_clicked" swapped="no"/>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
</child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
+ <property name="pack_type">end</property>
</packing>
</child>
</object>
diff --git a/data/ui/style.css b/data/ui/style.css
index de2f0f6d..67bd2ad3 100644
--- a/data/ui/style.css
+++ b/data/ui/style.css
@@ -42,6 +42,11 @@
.contacts-avatar-popover .contact-display-name {
font-size: 20px;
}
+flowboxchild.circular {
+ padding: 4px;
+ border-radius: 9999px;
+ -gtk-outline-radius: 9999px;
+}
.avatar-button {
border-radius: 50%;
diff --git a/src/contacts-avatar-selector.vala b/src/contacts-avatar-selector.vala
index 5f382894..1684b340 100644
--- a/src/contacts-avatar-selector.vala
+++ b/src/contacts-avatar-selector.vala
@@ -17,6 +17,44 @@
using Folks;
+const int MAIN_SIZE = 128;
+const int ICONS_SIZE = 64;
+
+private class Contacts.Thumbnail : Gtk.FlowBoxChild {
+ public Gdk.Pixbuf? source_pixbuf { get; construct set; }
+ private Thumbnail (Gdk.Pixbuf? source_pixbuf = null) {
+ Object (visible: true, halign : Gtk.Align.CENTER, source_pixbuf: source_pixbuf);
+ this.get_style_context ().add_class ("circular");
+ var avatar = new Avatar (ICONS_SIZE);
+ avatar.set_pixbuf (source_pixbuf);
+ add (avatar);
+ }
+
+ public Thumbnail.for_persona (Persona persona) {
+ Gdk.Pixbuf? pixbuf = null;
+ var details = persona as AvatarDetails;
+ if (details != null && details.avatar != null) {
+ try {
+ var stream = details.avatar.load (MAIN_SIZE, null);
+ pixbuf = new Gdk.Pixbuf.from_stream (stream);
+ } catch (Error e) {
+ debug ("Couldn't create frame for persona '%s': %s", persona.display_id, e.message);
+ }
+ }
+ this (pixbuf);
+ }
+
+ public Thumbnail.for_filename (string filename) {
+ Gdk.Pixbuf? pixbuf = null;
+ try {
+ pixbuf = new Gdk.Pixbuf.from_file (filename);
+ } catch (Error e) {
+ debug ("Couldn't create frame for file '%s': %s", filename, e.message);
+ }
+ this (pixbuf);
+ }
+}
+
/**
* The AvatarSelector can be used to choose the avatar for a contact.
* This can be done by either choosing a stock thumbnail, an image file
@@ -25,9 +63,7 @@ using Folks;
* After a user has initially chosen an avatar, we provide a cropping tool.
*/
[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-avatar-selector.ui")]
-public class Contacts.AvatarSelector : Gtk.Popover {
- const int ICONS_SIZE = 64;
- const int MAIN_SIZE = 128;
+public class Contacts.AvatarSelector : Gtk.Window {
const string AVATAR_BUTTON_CSS_NAME = "avatar-button";
// This will provide the default thumbnails
@@ -35,9 +71,7 @@ public class Contacts.AvatarSelector : Gtk.Popover {
private Individual individual;
[GtkChild]
- private Gtk.FlowBox personas_thumbnail_grid;
- [GtkChild]
- private Gtk.FlowBox stock_thumbnail_grid;
+ private Gtk.FlowBox thumbnail_grid;
#if HAVE_CHEESE
[GtkChild]
@@ -46,12 +80,19 @@ public class Contacts.AvatarSelector : Gtk.Popover {
private Cheese.CameraDeviceMonitor camera_monitor;
#endif
- public AvatarSelector (Gtk.Widget relative, Individual? individual) {
- this.set_relative_to(relative);
+ public AvatarSelector (Individual? individual, Gtk.Window? window = null) {
+ Object (transient_for: window);
this.thumbnail_factory = new Gnome.DesktopThumbnailFactory (Gnome.ThumbnailSize.NORMAL);
this.individual = individual;
- update_thumbnail_grids ();
+ unowned Gtk.BindingSet binding_set = Gtk.BindingSet.by_class (get_class ());
+ Gtk.BindingEntry.add_signal (binding_set,
+ Gdk.Key.Escape,
+ 0,
+ "close",
+ 0);
+
+ update_thumbnail_grid ();
#if HAVE_CHEESE
this.cheese_button.visible = true;
@@ -75,6 +116,16 @@ public class Contacts.AvatarSelector : Gtk.Popover {
#endif
}
+ [Signal (action = true)]
+ public new virtual signal void close () {
+ base.close ();
+ }
+
+ [GtkCallback]
+ public bool on_delete_event () {
+ return hide_on_delete ();
+ }
+
private Gdk.Pixbuf scale_pixbuf_for_avatar_use (Gdk.Pixbuf pixbuf) {
int w = pixbuf.get_width ();
int h = pixbuf.get_height ();
@@ -114,67 +165,22 @@ public class Contacts.AvatarSelector : Gtk.Popover {
get_toplevel() as Gtk.Window);
}
}
-
- private Gtk.FlowBoxChild create_thumbnail (Gdk.Pixbuf source_pixbuf) {
- var avatar = new Avatar (ICONS_SIZE);
- avatar.set_pixbuf (source_pixbuf);
-
- var button = new Gtk.Button ();
- button.get_style_context ().add_class (AVATAR_BUTTON_CSS_NAME);
- button.image = avatar;
- button.clicked.connect ( () => {
- selected_pixbuf (scale_pixbuf_for_avatar_use (source_pixbuf));
- this.popdown ();
- });
- var child = new Gtk.FlowBoxChild ();
- child.add (button);
- child.set_halign (Gtk.Align.START);
-
- return child;
- }
-
- private Gtk.FlowBoxChild? thumbnail_for_persona (Persona persona) {
- var details = persona as AvatarDetails;
- if (details == null || details.avatar == null)
- return null;
-
- try {
- var stream = details.avatar.load (MAIN_SIZE, null);
- return create_thumbnail (new Gdk.Pixbuf.from_stream (stream));
- } catch (Error e) {
- debug ("Couldn't create frame for persona '%s': %s", persona.display_id, e.message);
- }
-
- return null;
- }
-
- private Gtk.FlowBoxChild? thumbnail_for_filename (string filename) {
- try {
- return create_thumbnail (new Gdk.Pixbuf.from_file (filename));
- } catch (Error e) {
- debug ("Couldn't create frame for file '%s': %s", filename, e.message);
- }
-
- return null;
- }
-
- private void update_thumbnail_grids () {
+ private void update_thumbnail_grid () {
if (this.individual != null) {
foreach (var p in individual.personas) {
- var button = thumbnail_for_persona (p);
- if (button != null)
- this.personas_thumbnail_grid.add (button);
+ var widget = new Thumbnail.for_persona (p);
+ if (widget.source_pixbuf != null)
+ this.thumbnail_grid.add (widget);
}
}
- this.personas_thumbnail_grid.show_all ();
var stock_files = Utils.get_stock_avatars ();
foreach (var file_name in stock_files) {
- var button = thumbnail_for_filename (file_name);
- if (button != null)
- this.stock_thumbnail_grid.add (button);
+ var widget = new Thumbnail.for_filename (file_name);
+ if (widget.source_pixbuf != null)
+ this.thumbnail_grid.add (widget);
}
- this.stock_thumbnail_grid.show_all ();
+ this.thumbnail_grid.show_all ();
}
[GtkCallback]
@@ -183,8 +189,25 @@ public class Contacts.AvatarSelector : Gtk.Popover {
dialog.show_all ();
dialog.picture_selected.connect ( (pix) => {
selected_pixbuf (scale_pixbuf_for_avatar_use (pix));
+ this.close ();
});
- this.popdown ();
+ }
+
+ [GtkCallback]
+ private void on_cancel_clicked (Gtk.Button button) {
+ this.close ();
+ }
+
+ [GtkCallback]
+ private void on_done_clicked (Gtk.Button button) {
+ var selected_children = thumbnail_grid.get_selected_children ();
+ if (selected_children != null) {
+ var thumbnail = (selected_children.data as Thumbnail);
+ if (thumbnail != null)
+ selected_pixbuf (scale_pixbuf_for_avatar_use (thumbnail.source_pixbuf));
+ }
+
+ this.close ();
}
[GtkCallback]
@@ -233,11 +256,11 @@ public class Contacts.AvatarSelector : Gtk.Popover {
this.get_toplevel() as Gtk.Window);
}
- chooser.destroy ();
- });
+ chooser.destroy ();
+ });
chooser.run ();
- this.popdown();
+ this.close ();
}
private void update_preview (Gtk.FileChooser chooser) {
diff --git a/src/contacts-contact-editor.vala b/src/contacts-contact-editor.vala
index 09753c94..85c34f74 100644
--- a/src/contacts-contact-editor.vala
+++ b/src/contacts-contact-editor.vala
@@ -57,7 +57,7 @@ public class Contacts.ContactEditor : Gtk.Box {
// Show the avatar popover when the avatar is clicked
private void on_avatar_button_clicked (Gtk.Button avatar_button) {
if (this.avatar_selector == null)
- this.avatar_selector = new AvatarSelector (avatar_button, this.individual);
+ this.avatar_selector = new AvatarSelector (this.individual, (Gtk.Window) this.get_toplevel());
this.avatar_selector.show();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]