[gnome-control-center/gbsneto/background: 19/20] background: Manage recent backgrounds



commit fd4dc524f1a6f79e47a913a2515ee12a35bbd767
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Fri May 24 14:02:10 2019 -0300

    background: Manage recent backgrounds
    
    This is the last missing bit from the new Background panel, and
    puts the source added in the previous commit (BgRecentSource)
    in use.
    
    Nothing gloriously difficult is done here:
    
     * Add a headerbar button to open the file selector.
     * Hook it up in CcBackgroundChooser
     * Add a "Delete Background" button to the popover.

 panels/background/cc-background-chooser.c  | 199 +++++++++++++++++++++++++++--
 panels/background/cc-background-chooser.h  |   2 +
 panels/background/cc-background-chooser.ui |  64 ++++++++++
 panels/background/cc-background-panel.c    |  27 ++++
 panels/background/cc-background-panel.ui   |  48 +------
 5 files changed, 289 insertions(+), 51 deletions(-)
---
diff --git a/panels/background/cc-background-chooser.c b/panels/background/cc-background-chooser.c
index 070164ce1..ccf57964c 100644
--- a/panels/background/cc-background-chooser.c
+++ b/panels/background/cc-background-chooser.c
@@ -20,8 +20,11 @@
 
 #define G_LOG_DOMAIN "cc-background-chooser"
 
+#include <glib/gi18n.h>
+
 #include "bg-colors-source.h"
 #include "bg-pictures-source.h"
+#include "bg-recent-source.h"
 #include "bg-wallpapers-source.h"
 #include "cc-background-chooser.h"
 
@@ -30,9 +33,15 @@ struct _CcBackgroundChooser
   GtkBox              parent;
 
   GtkFlowBox         *flowbox;
+  GtkWidget          *popover_recent_box;
+  GtkWidget          *recent_box;
+  GtkFlowBox         *recent_flowbox;
   GtkPopover         *selection_popover;
 
+  gboolean            recent_selected;
+
   BgWallpapersSource *wallpapers_source;
+  BgRecentSource     *recent_source;
 };
 
 G_DEFINE_TYPE (CcBackgroundChooser, cc_background_chooser, GTK_TYPE_BOX)
@@ -51,13 +60,17 @@ emit_background_chosen (CcBackgroundChooser        *self,
 {
   g_autoptr(GList) list = NULL;
   CcBackgroundItem *item;
+  GtkFlowBox *flowbox;
 
-  list = gtk_flow_box_get_selected_children (self->flowbox);
+  flowbox = self->recent_selected ? self->recent_flowbox : self->flowbox;
+  list = gtk_flow_box_get_selected_children (flowbox);
   g_assert (g_list_length (list) == 1);
 
   item = g_object_get_data (list->data, "item");
 
   g_signal_emit (self, signals[BACKGROUND_CHOSEN], 0, item, flags);
+
+  gtk_flow_box_unselect_all (flowbox);
 }
 
 static GtkWidget*
@@ -65,20 +78,20 @@ create_widget_func (gpointer model_item,
                     gpointer user_data)
 {
   g_autoptr(GdkPixbuf) pixbuf = NULL;
-  CcBackgroundChooser *self;
   CcBackgroundItem *item;
   GtkWidget *overlay;
   GtkWidget *child;
   GtkWidget *image;
   GtkWidget *icon;
+  BgSource *source;
 
-  self = CC_BACKGROUND_CHOOSER (user_data);
+  source = BG_SOURCE (user_data);
   item = CC_BACKGROUND_ITEM (model_item);
   pixbuf = cc_background_item_get_thumbnail (item,
-                                             bg_source_get_thumbnail_factory (BG_SOURCE 
(self->wallpapers_source)),
-                                             bg_source_get_thumbnail_width (BG_SOURCE 
(self->wallpapers_source)),
-                                             bg_source_get_thumbnail_height (BG_SOURCE 
(self->wallpapers_source)),
-                                             bg_source_get_scale_factor (BG_SOURCE 
(self->wallpapers_source)));
+                                             bg_source_get_thumbnail_factory (source),
+                                             bg_source_get_thumbnail_width (source),
+                                             bg_source_get_thumbnail_height (source),
+                                             bg_source_get_scale_factor (source));
   image = gtk_image_new_from_pixbuf (pixbuf);
   gtk_widget_show (image);
 
@@ -109,6 +122,18 @@ create_widget_func (gpointer model_item,
   return child;
 }
 
+static void
+update_recent_visibility (CcBackgroundChooser *self)
+{
+  GListStore *store;
+  gboolean has_items;
+
+  store = bg_source_get_liststore (BG_SOURCE (self->recent_source));
+  has_items = g_list_model_get_n_items (G_LIST_MODEL (store)) != 0;
+
+  gtk_widget_set_visible (self->recent_box, has_items);
+}
+
 static void
 setup_flowbox (CcBackgroundChooser *self)
 {
@@ -119,8 +144,38 @@ setup_flowbox (CcBackgroundChooser *self)
   gtk_flow_box_bind_model (self->flowbox,
                            G_LIST_MODEL (store),
                            create_widget_func,
-                           self,
+                           self->wallpapers_source,
+                           NULL);
+
+  store = bg_source_get_liststore (BG_SOURCE (self->recent_source));
+
+  gtk_flow_box_bind_model (self->recent_flowbox,
+                           G_LIST_MODEL (store),
+                           create_widget_func,
+                           self->recent_source,
                            NULL);
+
+  update_recent_visibility (self);
+  g_signal_connect_object (store,
+                           "items-changed",
+                           G_CALLBACK (update_recent_visibility),
+                           self,
+                           G_CONNECT_SWAPPED);
+}
+
+static void
+on_delete_background_clicked_cb (GtkButton           *button,
+                                 CcBackgroundChooser *self)
+{
+  g_autoptr(GList) list = NULL;
+  CcBackgroundItem *item;
+
+  list = gtk_flow_box_get_selected_children (self->recent_flowbox);
+  g_assert (g_list_length (list) == 1);
+
+  item = g_object_get_data (list->data, "item");
+
+  bg_recent_source_remove_item (self->recent_source, item);
 }
 
 static void
@@ -152,10 +207,79 @@ on_item_activated_cb (GtkFlowBox          *flowbox,
                       GtkFlowBoxChild     *child,
                       CcBackgroundChooser *self)
 {
+  self->recent_selected = flowbox == self->recent_flowbox;
+  gtk_widget_set_visible (self->popover_recent_box, self->recent_selected);
+
   gtk_popover_set_relative_to (self->selection_popover, GTK_WIDGET (child));
   gtk_popover_popup (self->selection_popover);
 }
 
+static void
+on_file_chooser_response_cb (GtkDialog           *filechooser,
+                             gint                 response,
+                             CcBackgroundChooser *self)
+{
+  g_autofree gchar *filename = NULL;
+
+  if (response != GTK_RESPONSE_ACCEPT)
+    goto out;
+
+  filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser));
+
+  bg_recent_source_add_file (self->recent_source, filename);
+
+out:
+  gtk_widget_destroy (GTK_WIDGET (filechooser));
+}
+
+static void
+on_file_chooser_selection_changed_cb (GtkFileChooser               *chooser,
+                                      GnomeDesktopThumbnailFactory *thumbnail_factory)
+{
+  g_autofree gchar *uri = NULL;
+
+  uri = gtk_file_chooser_get_uri (chooser);
+
+  if (uri)
+    {
+      g_autoptr(GFileInfo) file_info = NULL;
+      g_autoptr(GdkPixbuf) pixbuf = NULL;
+      g_autofree gchar *mime_type = NULL;
+      g_autoptr(GFile) file = NULL;
+      GtkWidget *preview;
+
+      preview = gtk_file_chooser_get_preview_widget (chooser);
+
+      file = g_file_new_for_uri (uri);
+      file_info = g_file_query_info (file,
+                                     "standard::*",
+                                     G_FILE_QUERY_INFO_NONE,
+                                     NULL,
+                                     NULL);
+
+      if (file_info && g_file_info_get_file_type (file_info) != G_FILE_TYPE_DIRECTORY)
+        mime_type = g_strdup (g_file_info_get_content_type (file_info));
+
+      if (mime_type)
+        {
+          pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (thumbnail_factory,
+                                                                       uri,
+                                                                       mime_type);
+        }
+
+      gtk_dialog_set_response_sensitive (GTK_DIALOG (chooser),
+                                         GTK_RESPONSE_ACCEPT,
+                                         pixbuf != NULL);
+
+      if (pixbuf)
+        gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf);
+      else
+        gtk_image_set_from_icon_name (GTK_IMAGE (preview), "dialog-question", GTK_ICON_SIZE_DIALOG);
+    }
+
+  gtk_file_chooser_set_preview_widget_active (chooser, TRUE);
+}
+
 /* GObject overrides */
 
 static void
@@ -163,6 +287,7 @@ cc_background_chooser_finalize (GObject *object)
 {
   CcBackgroundChooser *self = (CcBackgroundChooser *)object;
 
+  g_clear_object (&self->recent_source);
   g_clear_object (&self->wallpapers_source);
 
   G_OBJECT_CLASS (cc_background_chooser_parent_class)->finalize (object);
@@ -188,8 +313,12 @@ cc_background_chooser_class_init (CcBackgroundChooserClass *klass)
   gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/control-center/background/cc-background-chooser.ui");
 
   gtk_widget_class_bind_template_child (widget_class, CcBackgroundChooser, flowbox);
+  gtk_widget_class_bind_template_child (widget_class, CcBackgroundChooser, popover_recent_box);
+  gtk_widget_class_bind_template_child (widget_class, CcBackgroundChooser, recent_box);
+  gtk_widget_class_bind_template_child (widget_class, CcBackgroundChooser, recent_flowbox);
   gtk_widget_class_bind_template_child (widget_class, CcBackgroundChooser, selection_popover);
 
+  gtk_widget_class_bind_template_callback (widget_class, on_delete_background_clicked_cb);
   gtk_widget_class_bind_template_callback (widget_class, on_item_activated_cb);
   gtk_widget_class_bind_template_callback (widget_class, on_selection_desktop_lock_clicked_cb);
   gtk_widget_class_bind_template_callback (widget_class, on_selection_desktop_clicked_cb);
@@ -201,6 +330,60 @@ cc_background_chooser_init (CcBackgroundChooser *self)
 {
   gtk_widget_init_template (GTK_WIDGET (self));
 
+  self->recent_source = bg_recent_source_new (GTK_WIDGET (self));
   self->wallpapers_source = bg_wallpapers_source_new (GTK_WIDGET (self));
   setup_flowbox (self);
 }
+
+void
+cc_background_chooser_select_file (CcBackgroundChooser *self)
+{
+  g_autoptr(GnomeDesktopThumbnailFactory) factory = NULL;
+  GtkFileFilter *filter;
+  GtkWidget *filechooser;
+  GtkWindow *toplevel;
+  GtkWidget *preview;
+
+  g_return_if_fail (CC_IS_BACKGROUND_CHOOSER (self));
+
+  toplevel = (GtkWindow*) gtk_widget_get_toplevel (GTK_WIDGET (self));
+  filechooser = gtk_file_chooser_dialog_new (_("Select a picture"),
+                                             toplevel,
+                                             GTK_FILE_CHOOSER_ACTION_OPEN,
+                                             _("_Cancel"), GTK_RESPONSE_CANCEL,
+                                             _("_Open"), GTK_RESPONSE_ACCEPT,
+                                             NULL);
+  gtk_window_set_modal (GTK_WINDOW (filechooser), TRUE);
+
+  preview = gtk_image_new ();
+  gtk_widget_set_size_request (preview, 256, -1);
+  gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (filechooser), preview);
+  gtk_file_chooser_set_use_preview_label (GTK_FILE_CHOOSER (filechooser), FALSE);
+  gtk_widget_show (preview);
+
+  factory = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_LARGE);
+  g_signal_connect_after (filechooser,
+                          "selection-changed",
+                          G_CALLBACK (on_file_chooser_selection_changed_cb),
+                          factory);
+
+  g_object_set_data_full (G_OBJECT (filechooser),
+                          "factory",
+                          g_object_ref (factory),
+                          g_object_unref);
+
+  filter = gtk_file_filter_new ();
+  gtk_file_filter_add_pixbuf_formats (filter);
+  gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (filechooser), filter);
+
+  gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filechooser),
+                                       g_get_user_special_dir (G_USER_DIRECTORY_PICTURES));
+
+  g_signal_connect_object (filechooser,
+                           "response",
+                           G_CALLBACK (on_file_chooser_response_cb),
+                           self,
+                           0);
+
+  gtk_window_present (GTK_WINDOW (filechooser));
+}
diff --git a/panels/background/cc-background-chooser.h b/panels/background/cc-background-chooser.h
index 6d88785e7..ced15191b 100644
--- a/panels/background/cc-background-chooser.h
+++ b/panels/background/cc-background-chooser.h
@@ -34,4 +34,6 @@ typedef enum
 #define CC_TYPE_BACKGROUND_CHOOSER (cc_background_chooser_get_type())
 G_DECLARE_FINAL_TYPE (CcBackgroundChooser, cc_background_chooser, CC, BACKGROUND_CHOOSER, GtkBox)
 
+void cc_background_chooser_select_file (CcBackgroundChooser *self);
+
 G_END_DECLS
diff --git a/panels/background/cc-background-chooser.ui b/panels/background/cc-background-chooser.ui
index 12e111a20..8e96e5691 100644
--- a/panels/background/cc-background-chooser.ui
+++ b/panels/background/cc-background-chooser.ui
@@ -29,6 +29,43 @@
             <style>
               <class name="view" />
             </style>
+
+            <!-- Recent -->
+            <child>
+              <object class="GtkBox" id="recent_box">
+                <property name="visible">True</property>
+                <property name="can-focus">True</property>
+                <property name="orientation">vertical</property>
+                <property name="halign">center</property>
+
+                <child>
+                  <object class="GtkFlowBox" id="recent_flowbox">
+                    <property name="visible">True</property>
+                    <property name="margin">12</property>
+                    <property name="column-spacing">12</property>
+                    <property name="row-spacing">12</property>
+                    <property name="homogeneous">True</property>
+                    <property name="halign">center</property>
+                    <property name="min-children-per-line">1</property>
+                    <property name="max-children-per-line">8</property>
+                    <property name="activate-on-single-click">True</property>
+                    <property name="selection-mode">single</property>
+                    <signal name="child-activated" handler="on_item_activated_cb" 
object="CcBackgroundChooser" swapped="no" />
+                  </object>
+                </child>
+
+                <child>
+                  <object class="GtkSeparator">
+                    <property name="visible">True</property>
+                    <property name="can-focus">True</property>
+                    <property name="margin-top">12</property>
+                    <property name="margin-bottom">12</property>
+                  </object>
+                </child>
+
+              </object>
+            </child>
+
             <child>
               <object class="GtkFlowBox" id="flowbox">
                 <property name="visible">True</property>
@@ -85,6 +122,33 @@
             <signal name="clicked" handler="on_selection_lock_clicked_cb" object="CcBackgroundChooser" 
swapped="no" />
           </object>
         </child>
+
+        <!-- Recent items section -->
+        <child>
+          <object class="GtkBox" id="popover_recent_box">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">6</property>
+            <child>
+              <object class="GtkSeparator">
+                <property name="visible">True</property>
+                <property name="margin-top">12</property>
+                <property name="margin-bottom">12</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkButton">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Delete Background</property>
+                <signal name="clicked" handler="on_delete_background_clicked_cb" 
object="CcBackgroundChooser" swapped="no" />
+                <style>
+                  <class name="destructive-action" />
+                </style>
+              </object>
+            </child>
+          </object>
+        </child>
       </object>
     </child>
   </object>
diff --git a/panels/background/cc-background-panel.c b/panels/background/cc-background-panel.c
index c4d32a1ec..ab62fdcf6 100644
--- a/panels/background/cc-background-panel.c
+++ b/panels/background/cc-background-panel.c
@@ -61,6 +61,8 @@ struct _CcBackgroundPanel
 
   GCancellable *copy_cancellable;
 
+  CcBackgroundChooser *background_chooser;
+  GtkWidget *add_picture_button;
   GtkWidget *bottom_hbox;
   CcBackgroundPreview *desktop_preview;
   CcBackgroundPreview *lock_screen_preview;
@@ -389,12 +391,33 @@ on_chooser_background_chosen_cb (CcBackgroundChooser        *chooser,
     set_background (self, self->lock_settings, item);
 }
 
+static void
+on_add_picture_button_clicked_cb (GtkWidget         *button,
+                                  CcBackgroundPanel *self)
+{
+  cc_background_chooser_select_file (self->background_chooser);
+}
+
 static const char *
 cc_background_panel_get_help_uri (CcPanel *panel)
 {
   return "help:gnome-help/look-background";
 }
 
+static void
+cc_background_panel_constructed (GObject *object)
+{
+  CcBackgroundPanel *self;
+  CcShell *shell;
+
+  self = CC_BACKGROUND_PANEL (object);
+  shell = cc_panel_get_shell (CC_PANEL (self));
+
+  cc_shell_embed_widget_in_header (shell, self->add_picture_button, GTK_POS_RIGHT);
+
+  G_OBJECT_CLASS (cc_background_panel_parent_class)->constructed (object);
+}
+
 static void
 cc_background_panel_dispose (GObject *object)
 {
@@ -436,16 +459,20 @@ cc_background_panel_class_init (CcBackgroundPanelClass *klass)
 
   panel_class->get_help_uri = cc_background_panel_get_help_uri;
 
+  object_class->constructed = cc_background_panel_constructed;
   object_class->dispose = cc_background_panel_dispose;
   object_class->finalize = cc_background_panel_finalize;
 
   gtk_widget_class_set_template_from_resource (widget_class, 
"/org/gnome/control-center/background/cc-background-panel.ui");
 
+  gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, add_picture_button);
+  gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, background_chooser);
   gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, bottom_hbox);
   gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, desktop_preview);
   gtk_widget_class_bind_template_child (widget_class, CcBackgroundPanel, lock_screen_preview);
 
   gtk_widget_class_bind_template_callback (widget_class, on_chooser_background_chosen_cb);
+  gtk_widget_class_bind_template_callback (widget_class, on_add_picture_button_clicked_cb);
 }
 
 static void
diff --git a/panels/background/cc-background-panel.ui b/panels/background/cc-background-panel.ui
index e606e01d9..066d3874a 100644
--- a/panels/background/cc-background-panel.ui
+++ b/panels/background/cc-background-panel.ui
@@ -72,48 +72,10 @@
     </child>
   </template>
 
-  <object class="GtkListStore" id="sources-liststore">
-    <columns>
-      <!-- column-name source-name -->
-      <column type="gchararray"/>
-      <!-- column-name source-id -->
-      <column type="guint"/>
-      <!-- column-name source-pointer -->
-      <column type="gpointer"/>
-    </columns>
-  </object>
-  <object class="GtkListStore" id="style-liststore">
-    <columns>
-      <!-- column-name name -->
-      <column type="gchararray"/>
-      <!-- column-name value -->
-      <column type="gint"/>
-    </columns>
-    <data>
-      <row>
-        <col id="0" translatable="yes" context="background, style">Tile</col>
-        <col id="1">1</col>
-      </row>
-      <row>
-        <col id="0" translatable="yes" context="background, style">Zoom</col>
-        <col id="1">5</col>
-      </row>
-      <row>
-        <col id="0" translatable="yes" context="background, style">Center</col>
-        <col id="1">2</col>
-      </row>
-      <row>
-        <col id="0" translatable="yes" context="background, style">Scale</col>
-        <col id="1">3</col>
-      </row>
-      <row>
-        <col id="0" translatable="yes" context="background, style">Fill</col>
-        <col id="1">4</col>
-      </row>
-      <row>
-        <col id="0" translatable="yes" context="background, style">Span</col>
-        <col id="1">6</col>
-      </row>
-    </data>
+  <!-- Header button -->
+  <object class="GtkButton" id="add_picture_button">
+    <property name="visible">True</property>
+    <property name="label" translatable="yes">Add Picture…</property>
+    <signal name="clicked" handler="on_add_picture_button_clicked_cb" object="CcBackgroundPanel" 
swapped="no" />
   </object>
 </interface>


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