[gnome-control-center/wip/gbsneto/list-layout] window: use a listbox
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-control-center/wip/gbsneto/list-layout] window: use a listbox
- Date: Wed, 25 May 2016 03:50:56 +0000 (UTC)
commit 7ad18bbf5a57ca28eae56ec1672ff31c2d929d27
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Tue May 24 23:52:02 2016 -0300
window: use a listbox
shell/cc-window.c | 472 +++++++++++++++--------------------------------------
shell/window.ui | 19 +--
2 files changed, 129 insertions(+), 362 deletions(-)
---
diff --git a/shell/cc-window.c b/shell/cc-window.c
index fba6613..201a26c 100644
--- a/shell/cc-window.c
+++ b/shell/cc-window.c
@@ -47,6 +47,15 @@
#define SEARCH_PAGE "_search"
#define OVERVIEW_PAGE "_overview"
+typedef struct
+{
+ GtkWidget *row;
+ GIcon *icon;
+ gchar *id;
+ gchar *name;
+ gchar *description;
+} RowData;
+
struct _CcWindow
{
GtkApplicationWindow parent;
@@ -55,7 +64,8 @@ struct _CcWindow
GtkWidget *header;
GtkWidget *header2;
GtkWidget *header_box;
- GtkWidget *main_vbox;
+ GtkWidget *listbox;
+ GtkWidget *list_scrolled;
GtkWidget *search_scrolled;
GtkWidget *top_right_box;
GtkWidget *search_button;
@@ -78,6 +88,8 @@ struct _CcWindow
gchar *filter_string;
gchar **filter_terms;
+ GHashTable *id_to_row;
+
CcPanel *active_panel;
};
@@ -119,6 +131,61 @@ get_icon_name_from_g_icon (GIcon *gicon)
return NULL;
}
+/*
+ * RowData functions
+ */
+static RowData*
+row_data_new (const gchar *id,
+ const gchar *name,
+ const gchar *description,
+ GIcon *icon)
+{
+ GtkWidget *label, *image, *grid;
+ RowData *data;
+
+ data = g_new0 (RowData, 1);
+ data->row = gtk_list_box_row_new ();
+ data->id = g_strdup (id);
+ data->name = g_strdup (name);
+ data->description = g_strdup (description);
+ data->icon = g_object_ref (icon);
+
+ /* Setup the row */
+ grid = g_object_new (GTK_TYPE_GRID,
+ "hexpand", TRUE,
+ "border-width", 12,
+ "column-spacing", 6,
+ NULL);
+
+ /* Icon */
+ image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_BUTTON);
+ gtk_grid_attach (GTK_GRID (grid), image, 0, 0, 1, 1);
+
+ /* Name label */
+ label = g_object_new (GTK_TYPE_LABEL,
+ "label", name,
+ "xalign", 0,
+ "hexpand", TRUE,
+ NULL);
+ gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
+
+ gtk_container_add (GTK_CONTAINER (data->row), grid);
+ gtk_widget_show_all (data->row);
+
+ g_object_set_data (G_OBJECT (data->row), "data", data);
+
+ return data;
+}
+
+static void
+row_data_free (RowData *data)
+{
+ g_object_unref (data->icon);
+ g_free (data->description);
+ g_free (data->name);
+ g_free (data);
+}
+
static gboolean
activate_panel (CcWindow *self,
const gchar *id,
@@ -248,292 +315,18 @@ cc_window_set_search_item (CcWindow *center,
}
static void
-item_activated_cb (CcShellCategoryView *view,
- gchar *name,
- gchar *id,
- CcWindow *shell)
-{
- cc_window_set_active_panel_from_id (CC_SHELL (shell), id, NULL, NULL);
-}
-
-static gboolean
-category_focus_out (GtkWidget *view,
- GdkEventFocus *event,
- CcWindow *shell)
-{
- gtk_icon_view_unselect_all (GTK_ICON_VIEW (view));
-
- return FALSE;
-}
-
-static gboolean
-category_focus_in (GtkWidget *view,
- GdkEventFocus *event,
- CcWindow *shell)
-{
- GtkTreePath *path;
-
- if (!gtk_icon_view_get_cursor (GTK_ICON_VIEW (view), &path, NULL))
- {
- path = gtk_tree_path_new_from_indices (0, -1);
- gtk_icon_view_set_cursor (GTK_ICON_VIEW (view), path, NULL, FALSE);
- }
-
- gtk_icon_view_select_path (GTK_ICON_VIEW (view), path);
- gtk_tree_path_free (path);
-
- return FALSE;
-}
-
-static GList *
-get_item_views (CcWindow *shell)
-{
- GList *list, *l;
- GList *res;
-
- list = gtk_container_get_children (GTK_CONTAINER (shell->main_vbox));
- res = NULL;
- for (l = list; l; l = l->next)
- {
- if (!CC_IS_SHELL_CATEGORY_VIEW (l->data))
- continue;
- res = g_list_append (res, cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (l->data)));
- }
-
- g_list_free (list);
-
- return res;
-}
-
-static gboolean
-is_prev_direction (GtkWidget *widget,
- GtkDirectionType direction)
-{
- if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR &&
- direction == GTK_DIR_LEFT)
- return TRUE;
- if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
- direction == GTK_DIR_RIGHT)
- return TRUE;
- return FALSE;
-}
-
-static gboolean
-is_next_direction (GtkWidget *widget,
- GtkDirectionType direction)
-{
- if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR &&
- direction == GTK_DIR_RIGHT)
- return TRUE;
- if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL &&
- direction == GTK_DIR_LEFT)
- return TRUE;
- return FALSE;
-}
-
-static GtkTreePath *
-get_first_path (GtkIconView *view)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
-
- model = gtk_icon_view_get_model (view);
- if (!gtk_tree_model_get_iter_first (model, &iter))
- return NULL;
- return gtk_tree_model_get_path (model, &iter);
-}
-
-static GtkTreePath *
-get_last_path (GtkIconView *view)
-{
- GtkTreeModel *model;
- GtkTreeIter iter;
- GtkTreePath *path;
- gboolean ret;
-
- model = gtk_icon_view_get_model (view);
- if (!gtk_tree_model_get_iter_first (model, &iter))
- return NULL;
-
- ret = TRUE;
- path = NULL;
-
- while (ret)
- {
- g_clear_pointer (&path, gtk_tree_path_free);
- path = gtk_tree_model_get_path (model, &iter);
- ret = gtk_tree_model_iter_next (model, &iter);
- }
- return path;
-}
-
-static gboolean
-categories_keynav_failed (GtkIconView *current_view,
- GtkDirectionType direction,
- CcWindow *shell)
+row_selected_cb (GtkListBox *listbox,
+ GtkListBoxRow *row,
+ CcWindow *self)
{
- GList *views, *v;
- GtkIconView *new_view;
- GtkTreePath *path;
- GtkTreeModel *model;
- GtkTreeIter iter;
- gint col, c, dist, d;
- GtkTreePath *sel;
- gboolean res;
-
- res = FALSE;
-
- views = get_item_views (shell);
-
- for (v = views; v; v = v->next)
- {
- if (v->data == current_view)
- break;
- }
-
- new_view = NULL;
-
- if (direction == GTK_DIR_DOWN && v != NULL && v->next != NULL)
- {
- new_view = v->next->data;
-
- if (gtk_icon_view_get_cursor (current_view, &path, NULL))
- {
- col = gtk_icon_view_get_item_column (current_view, path);
- gtk_tree_path_free (path);
-
- sel = NULL;
- dist = 1000;
- model = gtk_icon_view_get_model (new_view);
- g_assert (gtk_tree_model_get_iter_first (model, &iter));
- do {
- path = gtk_tree_model_get_path (model, &iter);
- c = gtk_icon_view_get_item_column (new_view, path);
- d = ABS (c - col);
- if (d < dist)
- {
- if (sel)
- gtk_tree_path_free (sel);
- sel = path;
- dist = d;
- }
- else
- gtk_tree_path_free (path);
- } while (gtk_tree_model_iter_next (model, &iter));
-
- gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE);
- gtk_tree_path_free (sel);
- }
-
- gtk_widget_grab_focus (GTK_WIDGET (new_view));
-
- res = TRUE;
- }
-
- if (direction == GTK_DIR_UP && v != NULL && v->prev != NULL)
- {
- new_view = v->prev->data;
-
- if (gtk_icon_view_get_cursor (current_view, &path, NULL))
- {
- col = gtk_icon_view_get_item_column (current_view, path);
- gtk_tree_path_free (path);
-
- sel = NULL;
- dist = 1000;
- model = gtk_icon_view_get_model (new_view);
- g_assert (gtk_tree_model_get_iter_first (model, &iter));
- do {
- path = gtk_tree_model_get_path (model, &iter);
- c = gtk_icon_view_get_item_column (new_view, path);
- d = ABS (c - col);
- if (d <= dist)
- {
- if (sel)
- gtk_tree_path_free (sel);
- sel = path;
- dist = d;
- }
- else
- gtk_tree_path_free (path);
- } while (gtk_tree_model_iter_next (model, &iter));
-
- gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE);
- gtk_tree_path_free (sel);
- }
-
- gtk_widget_grab_focus (GTK_WIDGET (new_view));
-
- res = TRUE;
- }
-
- if (is_prev_direction (GTK_WIDGET (current_view), direction) && v != NULL)
- {
- if (gtk_icon_view_get_cursor (current_view, &path, NULL))
- {
- if (v->prev)
- new_view = v->prev->data;
-
- if (gtk_tree_path_prev (path))
- {
- new_view = current_view;
- }
- else if (new_view != NULL)
- {
- path = get_last_path (new_view);
- }
- else
- {
- goto out;
- }
-
- gtk_icon_view_set_cursor (new_view, path, NULL, FALSE);
- gtk_icon_view_select_path (new_view, path);
- gtk_tree_path_free (path);
- gtk_widget_grab_focus (GTK_WIDGET (new_view));
-
- res = TRUE;
- }
- }
+ RowData *data;
- if (is_next_direction (GTK_WIDGET (current_view), direction) && v != NULL)
- {
- if (gtk_icon_view_get_cursor (current_view, &path, NULL))
- {
- GtkTreeIter iter;
-
- if (v->next)
- new_view = v->next->data;
-
- gtk_tree_path_next (path);
- model = gtk_icon_view_get_model (current_view);
-
- if (gtk_tree_model_get_iter (model, &iter, path))
- {
- new_view = current_view;
- }
- else if (new_view != NULL)
- {
- path = get_first_path (new_view);
- }
- else
- {
- goto out;
- }
-
- gtk_icon_view_set_cursor (new_view, path, NULL, FALSE);
- gtk_icon_view_select_path (new_view, path);
- gtk_tree_path_free (path);
- gtk_widget_grab_focus (GTK_WIDGET (new_view));
-
- res = TRUE;
- }
- }
+ if (!row)
+ return;
-out:
- g_list_free (views);
+ data = g_object_get_data (G_OBJECT (row), "data");
- return res;
+ cc_window_set_active_panel_from_id (CC_SHELL (self), data->id, NULL, NULL);
}
static gboolean
@@ -559,18 +352,6 @@ model_filter_func (GtkTreeModel *model,
return matches;
}
-static gboolean
-category_filter_func (GtkTreeModel *model,
- GtkTreeIter *iter,
- CcPanelCategory filter)
-{
- guint category;
-
- gtk_tree_model_get (model, iter, COL_CATEGORY, &category, -1);
-
- return (category == filter);
-}
-
static void
search_entry_changed_cb (GtkEntry *entry,
CcWindow *self)
@@ -797,61 +578,42 @@ setup_search (CcWindow *self)
}
static void
-add_category_view (CcWindow *shell,
- CcPanelCategory category,
- const char *name)
+setup_model (CcWindow *shell)
{
- GtkTreeModel *filter;
- GtkWidget *categoryview;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ shell->store = (GtkListStore *) cc_shell_model_new ();
+ model = GTK_TREE_MODEL (shell->store);
+
+ cc_panel_loader_fill_model (CC_SHELL_MODEL (shell->store));
+
+ /* Create a row for each panel */
+ gtk_tree_model_get_iter_first (model, &iter);
- if (category > 0)
+ while (gtk_tree_model_iter_next (model, &iter))
{
- GtkWidget *separator;
- separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
- gtk_widget_set_margin_top (separator, 11);
- gtk_widget_set_margin_bottom (separator, 10);
- gtk_box_pack_start (GTK_BOX (shell->main_vbox), separator, FALSE, FALSE, 0);
- gtk_widget_show (separator);
- }
+ RowData *data;
+ GIcon *icon;
+ gchar *name, *description, *id;
- /* create new category view for this category */
- filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (shell->store),
- NULL);
- gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter),
- (GtkTreeModelFilterVisibleFunc) category_filter_func,
- GINT_TO_POINTER (category), NULL);
-
- categoryview = cc_shell_category_view_new (name, filter);
- gtk_box_pack_start (GTK_BOX (shell->main_vbox), categoryview, FALSE, TRUE, 0);
-
- g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)),
- "desktop-item-activated",
- G_CALLBACK (item_activated_cb), shell);
-
- gtk_widget_show (categoryview);
-
- g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)),
- "focus-in-event",
- G_CALLBACK (category_focus_in), shell);
- g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)),
- "focus-out-event",
- G_CALLBACK (category_focus_out), shell);
- g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)),
- "keynav-failed",
- G_CALLBACK (categories_keynav_failed), shell);
-}
+ gtk_tree_model_get (model, &iter,
+ COL_DESCRIPTION, &description,
+ COL_GICON, &icon,
+ COL_ID, &id,
+ COL_NAME, &name,
+ -1);
-static void
-setup_model (CcWindow *shell)
-{
- shell->store = (GtkListStore *) cc_shell_model_new ();
+ data = row_data_new (id, name, description, icon);
- /* Add categories */
- add_category_view (shell, CC_CATEGORY_PERSONAL, C_("category", "Personal"));
- add_category_view (shell, CC_CATEGORY_HARDWARE, C_("category", "Hardware"));
- add_category_view (shell, CC_CATEGORY_SYSTEM, C_("category", "System"));
+ g_hash_table_insert (shell->id_to_row, id, data);
- cc_panel_loader_fill_model (CC_SHELL_MODEL (shell->store));
+ gtk_container_add (GTK_CONTAINER (shell->listbox), data->row);
+
+ g_clear_pointer (&description, g_free);
+ g_clear_pointer (&name, g_free);
+ g_clear_object (&icon);
+ }
}
static void
@@ -1152,6 +914,9 @@ cc_window_finalize (GObject *object)
g_free (self->filter_string);
g_strfreev (self->filter_terms);
+ g_hash_table_remove_all (self->id_to_row);
+ g_hash_table_destroy (self->id_to_row);
+
G_OBJECT_CLASS (cc_window_parent_class)->finalize (object);
}
@@ -1182,8 +947,8 @@ cc_window_class_init (CcWindowClass *klass)
gtk_widget_class_bind_template_child (widget_class, CcWindow, header2);
gtk_widget_class_bind_template_child (widget_class, CcWindow, header_box);
gtk_widget_class_bind_template_child (widget_class, CcWindow, header_sizegroup);
+ gtk_widget_class_bind_template_child (widget_class, CcWindow, list_scrolled);
gtk_widget_class_bind_template_child (widget_class, CcWindow, lock_button);
- gtk_widget_class_bind_template_child (widget_class, CcWindow, main_vbox);
gtk_widget_class_bind_template_child (widget_class, CcWindow, search_bar);
gtk_widget_class_bind_template_child (widget_class, CcWindow, search_button);
gtk_widget_class_bind_template_child (widget_class, CcWindow, search_entry);
@@ -1191,6 +956,7 @@ cc_window_class_init (CcWindowClass *klass)
gtk_widget_class_bind_template_child (widget_class, CcWindow, top_right_box);
gtk_widget_class_bind_template_callback (widget_class, gdk_window_set_cb);
+ gtk_widget_class_bind_template_callback (widget_class, row_selected_cb);
gtk_widget_class_bind_template_callback (widget_class, search_entry_changed_cb);
gtk_widget_class_bind_template_callback (widget_class, search_entry_key_press_event_cb);
gtk_widget_class_bind_template_callback (widget_class, sidelist_size_allocate_cb);
@@ -1300,6 +1066,19 @@ create_window (CcWindow *self)
gtk_window_set_titlebar (GTK_WINDOW (self), self->header_box);
gtk_widget_show_all (self->header_box);
+ /*
+ * We have to create the listbox here because declaring it in window.ui
+ * and letting GtkBuilder handle it would hit the bug where the focus is
+ * not tracked.
+ */
+ self->listbox = gtk_list_box_new ();
+ gtk_list_box_set_selection_mode (GTK_LIST_BOX (self->listbox), GTK_SELECTION_SINGLE);
+
+ g_signal_connect (self->listbox, "row-selected", G_CALLBACK (row_selected_cb), self);
+
+ gtk_container_add (GTK_CONTAINER (self->list_scrolled), self->listbox);
+ gtk_widget_show (self->listbox);
+
setup_model (self);
create_search_page (self);
@@ -1316,6 +1095,11 @@ cc_window_init (CcWindow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
+ self->id_to_row = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) row_data_free);
+
create_window (self);
self->previous_panels = g_queue_new ();
diff --git a/shell/window.ui b/shell/window.ui
index e6ceb33..b0cd3cd 100644
--- a/shell/window.ui
+++ b/shell/window.ui
@@ -45,28 +45,11 @@
</packing>
</child>
<child>
- <object class="GtkScrolledWindow">
+ <object class="GtkScrolledWindow" id="list_scrolled">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="vexpand">True</property>
<property name="hscrollbar_policy">never</property>
- <child>
- <object class="GtkViewport">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkBox" id="main_vbox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="border_width">12</property>
- <property name="orientation">vertical</property>
- <child>
- <placeholder/>
- </child>
- </object>
- </child>
- </object>
- </child>
<style>
<class name="view"/>
</style>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]