[file-roller/wip/gtk4] selector dialog: added a custom PlacesSidebar widget



commit 781ef3af03cc5105260c8d7109112fcb02dcc8fd
Author: Paolo Bacchilega <paobac src gnome org>
Date:   Sat Oct 15 13:43:35 2022 +0200

    selector dialog: added a custom PlacesSidebar widget

 src/fr-file-selector-dialog.c |  27 +++--
 src/fr-places-sidebar.c       | 258 ++++++++++++++++++++++++++++++++++++++++++
 src/fr-places-sidebar.h       |  42 +++++++
 src/meson.build               |   2 +
 src/ui/app.css                |  10 ++
 5 files changed, 327 insertions(+), 12 deletions(-)
---
diff --git a/src/fr-file-selector-dialog.c b/src/fr-file-selector-dialog.c
index 331d9c27..6b6d7bcb 100644
--- a/src/fr-file-selector-dialog.c
+++ b/src/fr-file-selector-dialog.c
@@ -23,6 +23,7 @@
 #include "fr-enum-types.h"
 #include "fr-file-selector-dialog.h"
 #include "fr-location-bar.h"
+#include "fr-places-sidebar.h"
 #include "gio-utils.h"
 #include "glib-utils.h"
 #include "gtk-utils.h"
@@ -113,6 +114,7 @@ struct _FrFileSelectorDialog {
        GtkPopover         *file_context_menu;
        GtkWidget          *location_bar;
        FrFileSelectorMode  selection_mode;
+       GtkWidget          *places_sidebar;
 };
 
 
@@ -202,7 +204,7 @@ set_current_folder (FrFileSelectorDialog *self,
                return;
 
        fr_location_bar_set_location (FR_LOCATION_BAR (self->location_bar), folder);
-       //gtk_places_sidebar_set_location (GTK_PLACES_SIDEBAR (GET_WIDGET ("places_sidebar")), folder);
+       fr_places_sidebar_set_location (FR_PLACES_SIDEBAR (self->places_sidebar), folder);
 }
 
 
@@ -561,16 +563,14 @@ location_bar_changed_cb (FrLocationBar *location_bar,
 }
 
 
-/*static void
-places_sidebar_open_location_cb (GtkPlacesSidebar  *sidebar,
-                                GFile             *location,
-                                GtkPlacesOpenFlags open_flags,
-                                gpointer           user_data)
+static void
+places_sidebar_open_cb (FrPlacesSidebar *sidebar,
+                       GFile           *location,
+                       gpointer         user_data)
 {
        FrFileSelectorDialog *self = user_data;
-
        fr_file_selector_dialog_set_current_folder (self, location);
-       }*/
+}
 
 
 static gboolean
@@ -712,6 +712,13 @@ fr_file_selector_dialog_init (FrFileSelectorDialog *self)
                          G_CALLBACK (location_bar_changed_cb),
                          self);
 
+       self->places_sidebar = fr_places_sidebar_new ();
+       _gtk_box_pack_start (GTK_BOX (GET_WIDGET ("places_sidebar")), self->places_sidebar, TRUE, TRUE);
+       g_signal_connect (self->places_sidebar,
+                         "open",
+                         G_CALLBACK (places_sidebar_open_cb),
+                         self);
+
        g_signal_connect (GTK_CELL_RENDERER_TOGGLE (GET_WIDGET ("is_selected_cellrenderertoggle")),
                          "toggled",
                          G_CALLBACK (is_selected_cellrenderertoggle_toggled_cb),
@@ -724,10 +731,6 @@ fr_file_selector_dialog_init (FrFileSelectorDialog *self)
                          "changed",
                          G_CALLBACK (files_treeview_selection_changed_cb),
                          self);
-       /*g_signal_connect (GTK_PLACES_SIDEBAR (GET_WIDGET ("places_sidebar")),
-                         "open-location",
-                         G_CALLBACK (places_sidebar_open_location_cb),
-                         self);*/
 
        GtkEventController *event_controller = gtk_event_controller_legacy_new ();
        g_signal_connect (event_controller,
diff --git a/src/fr-places-sidebar.c b/src/fr-places-sidebar.c
new file mode 100644
index 00000000..25552e46
--- /dev/null
+++ b/src/fr-places-sidebar.c
@@ -0,0 +1,258 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  File-Roller
+ *
+ *  Copyright (C) 2022 Free Software Foundation, 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/>.
+ */
+
+#include <config.h>
+#include "fr-enum-types.h"
+#include "fr-places-sidebar.h"
+#include "gio-utils.h"
+#include "glib-utils.h"
+#include "gtk-utils.h"
+
+
+enum {
+       OPEN,
+       LAST_SIGNAL
+};
+static guint fr_places_sidebar_signals[LAST_SIGNAL] = { 0 };
+
+
+typedef struct {
+       GtkWidget *list_box;
+} FrPlacesSidebarPrivate;
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (FrPlacesSidebar, fr_places_sidebar, GTK_TYPE_BOX)
+
+
+static void
+fr_places_sidebar_finalize (GObject *object)
+{
+       //FrPlacesSidebar *self = FR_PLACES_SIDEBAR (object);
+       G_OBJECT_CLASS (fr_places_sidebar_parent_class)->finalize (object);
+}
+
+
+static void
+fr_places_sidebar_class_init (FrPlacesSidebarClass *klass)
+{
+       GObjectClass *object_class;
+
+       object_class = (GObjectClass*) klass;
+       object_class->finalize = fr_places_sidebar_finalize;
+
+       fr_places_sidebar_signals[OPEN] =
+               g_signal_new ("open",
+                             G_TYPE_FROM_CLASS (klass),
+                             G_SIGNAL_RUN_LAST,
+                             G_STRUCT_OFFSET (FrPlacesSidebarClass, open),
+                             NULL, NULL,
+                             g_cclosure_marshal_VOID__OBJECT,
+                             G_TYPE_NONE,
+                             1, G_TYPE_OBJECT);
+}
+
+
+static GtkWidget *
+row_box_for_file (GFile      *file,
+                 const char *display_name)
+{
+       GFileInfo *info;
+
+       info = g_file_query_info (file,
+                                 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," 
G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON,
+                                 G_FILE_QUERY_INFO_NONE,
+                                 NULL,
+                                 NULL);
+       if (info == NULL)
+               return NULL;
+
+       GtkWidget *icon = gtk_image_new_from_gicon (g_file_info_get_symbolic_icon (info));
+       GtkWidget *label = gtk_label_new ((display_name != NULL) ? display_name : 
g_file_info_get_display_name (info));
+
+       GtkWidget *box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
+       gtk_box_append (GTK_BOX (box), icon);
+       gtk_box_append (GTK_BOX (box), label);
+
+       GtkWidget *row = gtk_list_box_row_new ();
+       gtk_style_context_add_class (gtk_widget_get_style_context (row), "fr-sidebar-row");
+       gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
+       g_object_set_data_full (G_OBJECT (row), "sidebar-file", g_object_ref (file), g_object_unref);
+
+       char *name = g_file_get_parse_name (file);
+       gtk_widget_set_tooltip_text (row, name);
+       g_free (name);
+
+       g_object_unref (info);
+
+       return row;
+}
+
+
+static void
+row_activated_cb (GtkListBox    *list_box,
+                 GtkListBoxRow *row,
+                 gpointer       user_data)
+{
+       FrPlacesSidebar *self = user_data;
+       GFile *file;
+
+       file = g_object_get_data (G_OBJECT (row), "sidebar-file");
+       if (file != NULL)
+               g_signal_emit (self,
+                              fr_places_sidebar_signals[OPEN],
+                              0,
+                              file);
+}
+
+
+static void
+fr_places_sidebar_init (FrPlacesSidebar *self)
+{
+       FrPlacesSidebarPrivate *private = fr_places_sidebar_get_instance_private (self);
+       GtkWidget *scrolled_window;
+
+       gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_VERTICAL);
+
+       scrolled_window = gtk_scrolled_window_new ();
+       gtk_widget_set_vexpand (scrolled_window, TRUE);
+       gtk_box_append (GTK_BOX (self), scrolled_window);
+
+       private->list_box = gtk_list_box_new ();
+       gtk_style_context_add_class (gtk_widget_get_style_context (private->list_box), "fr-sidebar");
+       gtk_list_box_set_activate_on_single_click (GTK_LIST_BOX (private->list_box), TRUE);
+       gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled_window), private->list_box);
+       g_signal_connect (private->list_box, "row-activated", G_CALLBACK (row_activated_cb), self);
+
+       GHashTable *locations = g_hash_table_new (g_file_hash, (GEqualFunc) g_file_equal);
+
+       /* Home */
+
+       GtkWidget *row;
+       GFile *location;
+
+       location = g_file_new_for_uri ("recent:///");
+       row = row_box_for_file (location, NULL);
+       if (row != NULL) {
+               gtk_list_box_append (GTK_LIST_BOX (private->list_box), row);
+               g_hash_table_add (locations, location);
+       }
+       g_object_unref (location);
+
+       location = g_file_new_for_uri ("starred:///");
+       row = row_box_for_file (location, NULL);
+       if (row != NULL) {
+               gtk_list_box_append (GTK_LIST_BOX (private->list_box), row);
+               g_hash_table_add (locations, location);
+       }
+       g_object_unref (location);
+
+       location = _g_file_get_home ();
+       row = row_box_for_file (location, _("Home"));
+       if (row != NULL) {
+               gtk_list_box_append (GTK_LIST_BOX (private->list_box), row);
+               g_hash_table_add (locations, location);
+       }
+
+       /* Special directories. */
+
+       location = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
+       row = row_box_for_file (location, NULL);
+       if (row != NULL) {
+               gtk_list_box_append (GTK_LIST_BOX (private->list_box), row);
+               g_hash_table_add (locations, location);
+       }
+       g_object_unref (location);
+
+       location = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_PICTURES));
+       row = row_box_for_file (location, NULL);
+       if (row != NULL) {
+               gtk_list_box_append (GTK_LIST_BOX (private->list_box), row);
+               g_hash_table_add (locations, location);
+       }
+       g_object_unref (location);
+
+       location = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_MUSIC));
+       row = row_box_for_file (location, NULL);
+       if (row != NULL) {
+               gtk_list_box_append (GTK_LIST_BOX (private->list_box), row);
+               g_hash_table_add (locations, location);
+       }
+       g_object_unref (location);
+
+       location = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD));
+       row = row_box_for_file (location, NULL);
+       if (row != NULL) {
+               gtk_list_box_append (GTK_LIST_BOX (private->list_box), row);
+               g_hash_table_add (locations, location);
+       }
+       g_object_unref (location);
+
+       location = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_VIDEOS));
+       row = row_box_for_file (location, NULL);
+       if (row != NULL) {
+               gtk_list_box_append (GTK_LIST_BOX (private->list_box), row);
+               g_hash_table_add (locations, location);
+       }
+       g_object_unref (location);
+
+       /* Bookmarks */
+
+       //gtk_list_box_append (GTK_LIST_BOX (private->list_box), gtk_separator_new 
(GTK_ORIENTATION_HORIZONTAL));
+
+       /* Root */
+
+       gtk_list_box_append (GTK_LIST_BOX (private->list_box), gtk_separator_new 
(GTK_ORIENTATION_HORIZONTAL));
+
+       location = g_file_new_for_path ("/");
+       row = row_box_for_file (location, NULL);
+       if (row != NULL) {
+               gtk_list_box_append (GTK_LIST_BOX (private->list_box), row);
+               g_hash_table_add (locations, location);
+       }
+       g_object_unref (location);
+
+       g_hash_table_unref (locations);
+}
+
+
+GtkWidget *
+fr_places_sidebar_new (void)
+{
+       return (GtkWidget *) g_object_new (fr_places_sidebar_get_type (), NULL);
+}
+
+
+void
+fr_places_sidebar_set_location (FrPlacesSidebar *self,
+                               GFile           *location)
+{
+       FrPlacesSidebarPrivate *private = fr_places_sidebar_get_instance_private (self);
+
+       gtk_list_box_unselect_all (GTK_LIST_BOX (private->list_box));
+       for (int i = 0; /* void */; i++) {
+               GtkListBoxRow *row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (private->list_box), i);
+               if (row == NULL)
+                       break;
+               GFile *file = g_object_get_data (G_OBJECT (row), "sidebar-file");
+               if ((file != NULL) && g_file_equal (file, location))
+                       gtk_list_box_select_row (GTK_LIST_BOX (private->list_box), row);
+       }
+}
diff --git a/src/fr-places-sidebar.h b/src/fr-places-sidebar.h
new file mode 100644
index 00000000..ed089e1d
--- /dev/null
+++ b/src/fr-places-sidebar.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ *  File-Roller
+ *
+ *  Copyright (C) 2022 The Free Software Foundation, 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/>.
+ */
+
+#ifndef FR_PLACES_SIDEBAR_H
+#define FR_PLACES_SIDEBAR_H
+
+#include <gtk/gtk.h>
+#include "typedefs.h"
+
+#define FR_TYPE_PLACES_SIDEBAR fr_places_sidebar_get_type ()
+G_DECLARE_DERIVABLE_TYPE (FrPlacesSidebar, fr_places_sidebar, FR, PLACES_SIDEBAR, GtkBox)
+
+struct _FrPlacesSidebarClass {
+       GtkBoxClass __parent_class;
+
+       /*< signals >*/
+
+       void (*open) (FrPlacesSidebar *self, GFile *location);
+};
+
+GtkWidget * fr_places_sidebar_new (void);
+void        fr_places_sidebar_set_location (FrPlacesSidebar *self, GFile *location);
+
+#endif /* FR_PLACES_SIDEBAR_H */
diff --git a/src/meson.build b/src/meson.build
index 94a07c4a..5d9e1c73 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -42,6 +42,7 @@ source_files = files(
   'fr-location-bar.c',
   'fr-location-button.c',
   'fr-new-archive-dialog.c',
+  'fr-places-sidebar.c',
   'fr-process.c',
   'fr-window-actions-callbacks.c',
   'fr-window.c',
@@ -86,6 +87,7 @@ fr_headers = files(
   'fr-location-bar.h',
   'fr-location-button.h',
   'fr-new-archive-dialog.h',
+  'fr-places-sidebar.h',
   'fr-process.h',
   'fr-window-actions-callbacks.h',
   'fr-window-actions-entries.h',
diff --git a/src/ui/app.css b/src/ui/app.css
index 53b48479..2513a55a 100644
--- a/src/ui/app.css
+++ b/src/ui/app.css
@@ -15,3 +15,13 @@
 .dialog-content.small-padding {
        padding: 10px;
 }
+
+.fr-sidebar {
+       padding: 6px;
+}
+
+.fr-sidebar-row {
+       border-radius: 6px;
+       padding: 7px 14px;
+       margin: 1px 0;
+}


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