panel-list: create a custom class to handle the sidelist
As the sidelist gets more complex, managing it in CcWindow would make it very confusing. This patch introduces the CcPanelList, a widget that manages the sidelist. https://bugzilla.gnome.org/show_bug.cgi?id=767301
This commit is contained in:
parent
2777fd583d
commit
cb1e0c4a01
6 changed files with 1095 additions and 0 deletions
|
@ -64,6 +64,12 @@ gnome_control_center_alt_SOURCES = \
|
||||||
gnome_control_center_LDFLAGS = -export-dynamic
|
gnome_control_center_LDFLAGS = -export-dynamic
|
||||||
gnome_control_center_alt_LDFLAGS = -export-dynamic
|
gnome_control_center_alt_LDFLAGS = -export-dynamic
|
||||||
|
|
||||||
|
# Temporarily add the CC_ENABLE_ALT_CATEGORIES compile-time
|
||||||
|
# flag to keep the current panels working.
|
||||||
|
gnome_control_center_alt_CPPFLAGS = \
|
||||||
|
$(AM_CPPFLAGS) \
|
||||||
|
-DCC_ENABLE_ALT_CATEGORIES
|
||||||
|
|
||||||
gnome_control_center_LDADD = \
|
gnome_control_center_LDADD = \
|
||||||
libshell.la \
|
libshell.la \
|
||||||
$(SHELL_LIBS) \
|
$(SHELL_LIBS) \
|
||||||
|
@ -153,6 +159,7 @@ EXTRA_DIST = \
|
||||||
$(completion_in_files) \
|
$(completion_in_files) \
|
||||||
gnome-control-center.gresource.xml \
|
gnome-control-center.gresource.xml \
|
||||||
help-overlay.ui \
|
help-overlay.ui \
|
||||||
|
panel-list.ui \
|
||||||
window.ui \
|
window.ui \
|
||||||
$(resource_files) \
|
$(resource_files) \
|
||||||
list-panel.sh
|
list-panel.sh
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
AM_CPPFLAGS = \
|
AM_CPPFLAGS = \
|
||||||
-DGNOMELOCALEDIR="\"$(datadir)/locale\""\
|
-DGNOMELOCALEDIR="\"$(datadir)/locale\""\
|
||||||
|
-DCC_ENABLE_ALT_CATEGORIES \
|
||||||
-I$(top_srcdir) \
|
-I$(top_srcdir) \
|
||||||
$(SHELL_CFLAGS) \
|
$(SHELL_CFLAGS) \
|
||||||
$(CHEESE_CFLAGS) \
|
$(CHEESE_CFLAGS) \
|
||||||
|
@ -11,6 +12,8 @@ AM_CPPFLAGS = \
|
||||||
noinst_LTLIBRARIES = libshell_alt.la
|
noinst_LTLIBRARIES = libshell_alt.la
|
||||||
|
|
||||||
libshell_alt_la_SOURCES = \
|
libshell_alt_la_SOURCES = \
|
||||||
|
cc-panel-list.c \
|
||||||
|
cc-panel-list.h \
|
||||||
cc-window.c \
|
cc-window.c \
|
||||||
cc-window.h
|
cc-window.h
|
||||||
|
|
||||||
|
|
808
shell/alt/cc-panel-list.c
Normal file
808
shell/alt/cc-panel-list.c
Normal file
|
@ -0,0 +1,808 @@
|
||||||
|
/* cc-panel-list.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Endless, 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/>.
|
||||||
|
*
|
||||||
|
* Author: Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "cc-panel-list.h"
|
||||||
|
#include "cc-util.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GtkWidget *row;
|
||||||
|
GtkWidget *description_label;
|
||||||
|
CcPanelCategory category;
|
||||||
|
gchar *id;
|
||||||
|
gchar *name;
|
||||||
|
gchar *description;
|
||||||
|
} RowData;
|
||||||
|
|
||||||
|
struct _CcPanelList
|
||||||
|
{
|
||||||
|
GtkStack parent;
|
||||||
|
|
||||||
|
GtkWidget *details_listbox;
|
||||||
|
GtkWidget *devices_listbox;
|
||||||
|
GtkWidget *main_listbox;
|
||||||
|
GtkWidget *search_listbox;
|
||||||
|
|
||||||
|
GtkListBoxRow *details_row;
|
||||||
|
GtkListBoxRow *devices_row;
|
||||||
|
|
||||||
|
GtkWidget *empty_search_placeholder;
|
||||||
|
|
||||||
|
gchar *search_query;
|
||||||
|
|
||||||
|
CcPanelListView previous_view;
|
||||||
|
CcPanelListView view;
|
||||||
|
};
|
||||||
|
|
||||||
|
G_DEFINE_TYPE (CcPanelList, cc_panel_list, GTK_TYPE_STACK)
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_SEARCH_MODE,
|
||||||
|
PROP_SEARCH_QUERY,
|
||||||
|
PROP_VIEW,
|
||||||
|
N_PROPS
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SHOW_PANEL,
|
||||||
|
LAST_SIGNAL
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *properties [N_PROPS] = { NULL, };
|
||||||
|
static gint signals [LAST_SIGNAL] = { 0, };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Auxiliary methods
|
||||||
|
*/
|
||||||
|
static GtkWidget*
|
||||||
|
get_listbox_from_view (CcPanelList *self,
|
||||||
|
CcPanelListView view)
|
||||||
|
{
|
||||||
|
switch (view)
|
||||||
|
{
|
||||||
|
case CC_PANEL_LIST_MAIN:
|
||||||
|
return self->main_listbox;
|
||||||
|
|
||||||
|
case CC_PANEL_LIST_DETAILS:
|
||||||
|
return self->details_listbox;
|
||||||
|
|
||||||
|
case CC_PANEL_LIST_DEVICES:
|
||||||
|
return self->devices_listbox;
|
||||||
|
|
||||||
|
case CC_PANEL_LIST_SEARCH:
|
||||||
|
return self->search_listbox;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CcPanelListView
|
||||||
|
get_view_from_listbox (CcPanelList *self,
|
||||||
|
GtkWidget *listbox)
|
||||||
|
{
|
||||||
|
if (listbox == self->main_listbox)
|
||||||
|
return CC_PANEL_LIST_MAIN;
|
||||||
|
|
||||||
|
if (listbox == self->details_listbox)
|
||||||
|
return CC_PANEL_LIST_DETAILS;
|
||||||
|
|
||||||
|
if (listbox == self->devices_listbox)
|
||||||
|
return CC_PANEL_LIST_DEVICES;
|
||||||
|
|
||||||
|
return CC_PANEL_LIST_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_search (CcPanelList *self)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Only change to the search view is there's a
|
||||||
|
* search query available.
|
||||||
|
*/
|
||||||
|
if (self->search_query &&
|
||||||
|
g_utf8_strlen (self->search_query, -1) > 0)
|
||||||
|
{
|
||||||
|
if (self->view == CC_PANEL_LIST_MAIN)
|
||||||
|
cc_panel_list_set_view (self, CC_PANEL_LIST_SEARCH);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (self->view == CC_PANEL_LIST_SEARCH)
|
||||||
|
cc_panel_list_set_view (self, self->previous_view);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_list_box_invalidate_filter (GTK_LIST_BOX (self->search_listbox));
|
||||||
|
gtk_list_box_unselect_all (GTK_LIST_BOX (self->search_listbox));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RowData functions
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
row_data_free (RowData *data)
|
||||||
|
{
|
||||||
|
g_free (data->description);
|
||||||
|
g_free (data->name);
|
||||||
|
g_free (data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RowData*
|
||||||
|
row_data_new (CcPanelCategory category,
|
||||||
|
const gchar *id,
|
||||||
|
const gchar *name,
|
||||||
|
const gchar *description,
|
||||||
|
const gchar *icon)
|
||||||
|
{
|
||||||
|
GtkWidget *label, *grid, *image;
|
||||||
|
RowData *data;
|
||||||
|
|
||||||
|
data = g_new0 (RowData, 1);
|
||||||
|
data->category = category;
|
||||||
|
data->row = gtk_list_box_row_new ();
|
||||||
|
data->id = g_strdup (id);
|
||||||
|
data->name = g_strdup (name);
|
||||||
|
data->description = g_strdup (description);
|
||||||
|
|
||||||
|
/* Setup the row */
|
||||||
|
grid = g_object_new (GTK_TYPE_GRID,
|
||||||
|
"visible", TRUE,
|
||||||
|
"hexpand", TRUE,
|
||||||
|
"border-width", 12,
|
||||||
|
"column-spacing", 12,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Icon */
|
||||||
|
image = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_BUTTON);
|
||||||
|
gtk_style_context_add_class (gtk_widget_get_style_context (image), "dim-label");
|
||||||
|
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), image, 0, 0, 1, 1);
|
||||||
|
|
||||||
|
gtk_widget_show (image);
|
||||||
|
|
||||||
|
/* Name label */
|
||||||
|
label = g_object_new (GTK_TYPE_LABEL,
|
||||||
|
"label", name,
|
||||||
|
"visible", TRUE,
|
||||||
|
"xalign", 0.0,
|
||||||
|
"hexpand", TRUE,
|
||||||
|
NULL);
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
|
||||||
|
|
||||||
|
/* Description label */
|
||||||
|
label = g_object_new (GTK_TYPE_LABEL,
|
||||||
|
"label", description,
|
||||||
|
"visible", FALSE,
|
||||||
|
"xalign", 0.0,
|
||||||
|
"hexpand", TRUE,
|
||||||
|
NULL);
|
||||||
|
gtk_label_set_max_width_chars (GTK_LABEL (label), 25);
|
||||||
|
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
|
||||||
|
|
||||||
|
gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), label, 1, 1, 1, 1);
|
||||||
|
|
||||||
|
data->description_label = label;
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (data->row), grid);
|
||||||
|
gtk_widget_show (data->row);
|
||||||
|
|
||||||
|
g_object_set_data_full (G_OBJECT (data->row), "data", data, (GDestroyNotify) row_data_free);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GtkListBox functions
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
filter_func (GtkListBoxRow *row,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CcPanelList *self;
|
||||||
|
RowData *data;
|
||||||
|
gchar *search_text, *panel_text, *panel_description;
|
||||||
|
gboolean retval;
|
||||||
|
|
||||||
|
self = CC_PANEL_LIST (user_data);
|
||||||
|
data = g_object_get_data (G_OBJECT (row), "data");
|
||||||
|
|
||||||
|
if (!self->search_query)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
panel_text = cc_util_normalize_casefold_and_unaccent (data->name);
|
||||||
|
search_text = cc_util_normalize_casefold_and_unaccent (self->search_query);
|
||||||
|
panel_description = cc_util_normalize_casefold_and_unaccent (data->description);
|
||||||
|
|
||||||
|
g_strstrip (panel_text);
|
||||||
|
g_strstrip (search_text);
|
||||||
|
g_strstrip (panel_description);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The description label is only visible when the search is
|
||||||
|
* happening.
|
||||||
|
*/
|
||||||
|
gtk_widget_set_visible (data->description_label, self->view == CC_PANEL_LIST_SEARCH);
|
||||||
|
|
||||||
|
retval = g_strstr_len (panel_text, -1, search_text) != NULL ||
|
||||||
|
g_strstr_len (panel_description, -1, search_text) != NULL;
|
||||||
|
|
||||||
|
g_free (panel_text);
|
||||||
|
g_free (search_text);
|
||||||
|
g_free (panel_description);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
sort_function (GtkListBoxRow *a,
|
||||||
|
GtkListBoxRow *b,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CcPanelList *self;
|
||||||
|
RowData *a_data, *b_data;
|
||||||
|
|
||||||
|
self = CC_PANEL_LIST (user_data);
|
||||||
|
|
||||||
|
/* Handle the Devices and the Details rows */
|
||||||
|
if (a == self->details_row && b == self->devices_row)
|
||||||
|
return 1;
|
||||||
|
if (a == self->devices_row && b == self->details_row)
|
||||||
|
return -1;
|
||||||
|
if (a == self->details_row || a == self->devices_row)
|
||||||
|
return 1;
|
||||||
|
if (b == self->details_row || b == self->devices_row)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can only retrieve the data after assuring that none
|
||||||
|
* of the rows are Devices and Details.
|
||||||
|
*/
|
||||||
|
a_data = g_object_get_data (G_OBJECT (a), "data");
|
||||||
|
b_data = g_object_get_data (G_OBJECT (b), "data");
|
||||||
|
|
||||||
|
if (a_data->category != b_data->category)
|
||||||
|
return a_data->category - b_data->category;
|
||||||
|
|
||||||
|
return g_strcmp0 (a_data->name, b_data->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
search_sort_function (GtkListBoxRow *a,
|
||||||
|
GtkListBoxRow *b,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CcPanelList *self;
|
||||||
|
RowData *a_data, *b_data;
|
||||||
|
gchar *a_name, *b_name, *search, *a_strstr, *b_strstr;
|
||||||
|
gint a_distance, b_distance;
|
||||||
|
gint retval;
|
||||||
|
|
||||||
|
self = CC_PANEL_LIST (user_data);
|
||||||
|
search = NULL;
|
||||||
|
a_data = g_object_get_data (G_OBJECT (a), "data");
|
||||||
|
b_data = g_object_get_data (G_OBJECT (b), "data");
|
||||||
|
|
||||||
|
a_distance = b_distance = G_MAXINT;
|
||||||
|
|
||||||
|
a_name = cc_util_normalize_casefold_and_unaccent (a_data->name);
|
||||||
|
b_name = cc_util_normalize_casefold_and_unaccent (b_data->name);
|
||||||
|
g_strstrip (a_name);
|
||||||
|
g_strstrip (b_name);
|
||||||
|
|
||||||
|
if (self->search_query)
|
||||||
|
{
|
||||||
|
search = cc_util_normalize_casefold_and_unaccent (self->search_query);
|
||||||
|
g_strstrip (search);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default result for empty search */
|
||||||
|
if (!search || g_utf8_strlen (search, -1) == 0)
|
||||||
|
{
|
||||||
|
retval = g_strcmp0 (a_name, b_name);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
a_strstr = g_strstr_len (a_name, -1, search);
|
||||||
|
b_strstr = g_strstr_len (b_name, -1, search);
|
||||||
|
|
||||||
|
if (a_strstr)
|
||||||
|
a_distance = g_strstr_len (a_name, -1, search) - a_name;
|
||||||
|
|
||||||
|
if (b_strstr)
|
||||||
|
b_distance = g_strstr_len (b_name, -1, search) - b_name;
|
||||||
|
|
||||||
|
retval = a_distance - b_distance;
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_free (a_name);
|
||||||
|
g_free (b_name);
|
||||||
|
g_free (search);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
header_func (GtkListBoxRow *row,
|
||||||
|
GtkListBoxRow *before,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CcPanelList *self = CC_PANEL_LIST (user_data);
|
||||||
|
|
||||||
|
if (!before)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* The Details row always have the separator */
|
||||||
|
if (row == self->details_row)
|
||||||
|
{
|
||||||
|
GtkWidget *separator;
|
||||||
|
|
||||||
|
separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
|
||||||
|
gtk_widget_set_hexpand (separator, TRUE);
|
||||||
|
gtk_widget_show (separator);
|
||||||
|
|
||||||
|
gtk_list_box_row_set_header (row, separator);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RowData *row_data, *before_data;
|
||||||
|
|
||||||
|
if (row == self->devices_row ||
|
||||||
|
before == self->details_row ||
|
||||||
|
before == self->devices_row)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can only retrieve the data after assuring that none
|
||||||
|
* of the rows are Devices and Details.
|
||||||
|
*/
|
||||||
|
row_data = g_object_get_data (G_OBJECT (row), "data");
|
||||||
|
before_data = g_object_get_data (G_OBJECT (before), "data");
|
||||||
|
|
||||||
|
if (row_data->category != before_data->category)
|
||||||
|
{
|
||||||
|
GtkWidget *separator;
|
||||||
|
|
||||||
|
separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
|
||||||
|
gtk_widget_set_hexpand (separator, TRUE);
|
||||||
|
gtk_widget_show (separator);
|
||||||
|
|
||||||
|
gtk_list_box_row_set_header (row, separator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Callbacks
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
row_activated_cb (GtkWidget *listbox,
|
||||||
|
GtkListBoxRow *row,
|
||||||
|
CcPanelList *self)
|
||||||
|
{
|
||||||
|
RowData *data;
|
||||||
|
|
||||||
|
/* Details */
|
||||||
|
if (row == self->details_row)
|
||||||
|
{
|
||||||
|
cc_panel_list_set_view (self, CC_PANEL_LIST_DETAILS);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Devices */
|
||||||
|
if (row == self->devices_row)
|
||||||
|
{
|
||||||
|
cc_panel_list_set_view (self, CC_PANEL_LIST_DEVICES);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When a panel is selected, the previous one should be
|
||||||
|
* unselected, except when it's search.
|
||||||
|
*/
|
||||||
|
if (listbox != self->search_listbox)
|
||||||
|
{
|
||||||
|
if (listbox != self->main_listbox)
|
||||||
|
gtk_list_box_unselect_all (GTK_LIST_BOX (self->main_listbox));
|
||||||
|
|
||||||
|
if (listbox != self->details_listbox)
|
||||||
|
gtk_list_box_unselect_all (GTK_LIST_BOX (self->details_listbox));
|
||||||
|
|
||||||
|
if (listbox != self->devices_listbox)
|
||||||
|
gtk_list_box_unselect_all (GTK_LIST_BOX (self->devices_listbox));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since we're not sure that the activated row is in the
|
||||||
|
* current view, set the view here.
|
||||||
|
*/
|
||||||
|
cc_panel_list_set_view (self, get_view_from_listbox (self, listbox));
|
||||||
|
|
||||||
|
data = g_object_get_data (G_OBJECT (row), "data");
|
||||||
|
|
||||||
|
g_signal_emit (self, signals[SHOW_PANEL], 0, data->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
search_row_activated_cb (GtkWidget *listbox,
|
||||||
|
GtkListBoxRow *row,
|
||||||
|
CcPanelList *self)
|
||||||
|
{
|
||||||
|
GtkWidget *real_listbox;
|
||||||
|
RowData *data;
|
||||||
|
GList *children, *l;
|
||||||
|
|
||||||
|
data = g_object_get_data (G_OBJECT (row), "data");
|
||||||
|
|
||||||
|
if (data->category == CC_CATEGORY_DETAILS)
|
||||||
|
real_listbox = self->details_listbox;
|
||||||
|
else if (data->category == CC_CATEGORY_DEVICES)
|
||||||
|
real_listbox = self->devices_listbox;
|
||||||
|
else
|
||||||
|
real_listbox = self->main_listbox;
|
||||||
|
|
||||||
|
/* Select the correct row */
|
||||||
|
children = gtk_container_get_children (GTK_CONTAINER (real_listbox));
|
||||||
|
|
||||||
|
for (l = children; l != NULL; l = l->next)
|
||||||
|
{
|
||||||
|
RowData *real_row_data;
|
||||||
|
|
||||||
|
real_row_data = g_object_get_data (l->data, "data");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The main listbox has the Details & Devices rows, and neither
|
||||||
|
* of them contains "data", so we have to ensure we have valid
|
||||||
|
* data before going on.
|
||||||
|
*/
|
||||||
|
if (!real_row_data)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (g_strcmp0 (real_row_data->id, data->id) == 0)
|
||||||
|
{
|
||||||
|
GtkListBoxRow *real_row;
|
||||||
|
|
||||||
|
real_row = GTK_LIST_BOX_ROW (real_row_data->row);
|
||||||
|
|
||||||
|
gtk_list_box_select_row (GTK_LIST_BOX (real_listbox), real_row);
|
||||||
|
gtk_widget_grab_focus (GTK_WIDGET (real_row));
|
||||||
|
|
||||||
|
g_signal_emit_by_name (real_row, "activate");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free (children);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_panel_list_finalize (GObject *object)
|
||||||
|
{
|
||||||
|
CcPanelList *self = (CcPanelList *)object;
|
||||||
|
|
||||||
|
g_clear_pointer (&self->search_query, g_free);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (cc_panel_list_parent_class)->finalize (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_panel_list_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
CcPanelList *self = CC_PANEL_LIST (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_SEARCH_MODE:
|
||||||
|
g_value_set_boolean (value, self->view == CC_PANEL_LIST_SEARCH);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_SEARCH_QUERY:
|
||||||
|
g_value_set_string (value, self->search_query);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_VIEW:
|
||||||
|
g_value_set_int (value, self->view);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_panel_list_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
CcPanelList *self = CC_PANEL_LIST (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_SEARCH_MODE:
|
||||||
|
update_search (self);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_SEARCH_QUERY:
|
||||||
|
cc_panel_list_set_search_query (self, g_value_get_string (value));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_VIEW:
|
||||||
|
cc_panel_list_set_view (self, g_value_get_int (value));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_panel_list_class_init (CcPanelListClass *klass)
|
||||||
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||||
|
|
||||||
|
object_class->finalize = cc_panel_list_finalize;
|
||||||
|
object_class->get_property = cc_panel_list_get_property;
|
||||||
|
object_class->set_property = cc_panel_list_set_property;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CcPanelList:show-panel:
|
||||||
|
*
|
||||||
|
* Emited when a panel is selected.
|
||||||
|
*/
|
||||||
|
signals[SHOW_PANEL] = g_signal_new ("show-panel",
|
||||||
|
CC_TYPE_PANEL_LIST,
|
||||||
|
G_SIGNAL_RUN_LAST,
|
||||||
|
0, NULL, NULL, NULL,
|
||||||
|
G_TYPE_NONE,
|
||||||
|
1,
|
||||||
|
G_TYPE_STRING);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CcPanelList:search-mode:
|
||||||
|
*
|
||||||
|
* Whether the search is visible or not.
|
||||||
|
*/
|
||||||
|
properties[PROP_SEARCH_MODE] = g_param_spec_boolean ("search-mode",
|
||||||
|
"Search mode",
|
||||||
|
"Whether it's in search mode or not",
|
||||||
|
FALSE,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CcPanelList:search-query:
|
||||||
|
*
|
||||||
|
* The search that is being applied to sidelist.
|
||||||
|
*/
|
||||||
|
properties[PROP_SEARCH_QUERY] = g_param_spec_string ("search-query",
|
||||||
|
"Search query",
|
||||||
|
"The current search query",
|
||||||
|
NULL,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CcPanelList:view:
|
||||||
|
*
|
||||||
|
* The current view of the sidelist.
|
||||||
|
*/
|
||||||
|
properties[PROP_VIEW] = g_param_spec_int ("view",
|
||||||
|
"View",
|
||||||
|
"The current view of the sidelist",
|
||||||
|
CC_PANEL_LIST_MAIN,
|
||||||
|
CC_PANEL_LIST_SEARCH,
|
||||||
|
CC_PANEL_LIST_MAIN,
|
||||||
|
G_PARAM_READWRITE);
|
||||||
|
|
||||||
|
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||||
|
|
||||||
|
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/ControlCenter/gtk/panel-list.ui");
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcPanelList, details_listbox);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcPanelList, details_row);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcPanelList, devices_listbox);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcPanelList, devices_row);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcPanelList, empty_search_placeholder);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcPanelList, main_listbox);
|
||||||
|
gtk_widget_class_bind_template_child (widget_class, CcPanelList, search_listbox);
|
||||||
|
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, row_activated_cb);
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, search_row_activated_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cc_panel_list_init (CcPanelList *self)
|
||||||
|
{
|
||||||
|
gtk_widget_init_template (GTK_WIDGET (self));
|
||||||
|
|
||||||
|
self->view = CC_PANEL_LIST_MAIN;
|
||||||
|
|
||||||
|
gtk_list_box_set_sort_func (GTK_LIST_BOX (self->main_listbox),
|
||||||
|
sort_function,
|
||||||
|
self,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gtk_list_box_set_header_func (GTK_LIST_BOX (self->main_listbox),
|
||||||
|
header_func,
|
||||||
|
self,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Search listbox */
|
||||||
|
gtk_list_box_set_sort_func (GTK_LIST_BOX (self->search_listbox),
|
||||||
|
search_sort_function,
|
||||||
|
self,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gtk_list_box_set_filter_func (GTK_LIST_BOX (self->search_listbox),
|
||||||
|
filter_func,
|
||||||
|
self,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
gtk_list_box_set_placeholder (GTK_LIST_BOX (self->search_listbox), self->empty_search_placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWidget*
|
||||||
|
cc_panel_list_new (void)
|
||||||
|
{
|
||||||
|
return g_object_new (CC_TYPE_PANEL_LIST, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
cc_panel_list_activate (CcPanelList *self)
|
||||||
|
{
|
||||||
|
GtkListBoxRow *row;
|
||||||
|
GtkWidget *listbox;
|
||||||
|
|
||||||
|
g_return_val_if_fail (CC_IS_PANEL_LIST (self), FALSE);
|
||||||
|
|
||||||
|
listbox = get_listbox_from_view (self, self->view);
|
||||||
|
|
||||||
|
if (self->view == CC_PANEL_LIST_SEARCH)
|
||||||
|
row = gtk_list_box_get_row_at_y (GTK_LIST_BOX (listbox), 0);
|
||||||
|
else
|
||||||
|
row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (listbox), 0);
|
||||||
|
|
||||||
|
/* If the row is valid, activate it */
|
||||||
|
if (row)
|
||||||
|
{
|
||||||
|
gtk_list_box_select_row (GTK_LIST_BOX (listbox), row);
|
||||||
|
gtk_widget_grab_focus (GTK_WIDGET (row));
|
||||||
|
|
||||||
|
g_signal_emit_by_name (row, "activate");
|
||||||
|
}
|
||||||
|
|
||||||
|
return row != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gchar*
|
||||||
|
cc_panel_list_get_search_query (CcPanelList *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (CC_IS_PANEL_LIST (self), NULL);
|
||||||
|
|
||||||
|
return self->search_query;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cc_panel_list_set_search_query (CcPanelList *self,
|
||||||
|
const gchar *search)
|
||||||
|
{
|
||||||
|
g_return_if_fail (CC_IS_PANEL_LIST (self));
|
||||||
|
|
||||||
|
if (g_strcmp0 (self->search_query, search) != 0)
|
||||||
|
{
|
||||||
|
g_clear_pointer (&self->search_query, g_free);
|
||||||
|
self->search_query = g_strdup (search);
|
||||||
|
|
||||||
|
update_search (self);
|
||||||
|
|
||||||
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SEARCH_QUERY]);
|
||||||
|
|
||||||
|
gtk_list_box_invalidate_filter (GTK_LIST_BOX (self->search_listbox));
|
||||||
|
gtk_list_box_invalidate_sort (GTK_LIST_BOX (self->search_listbox));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CcPanelListView
|
||||||
|
cc_panel_list_get_view (CcPanelList *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (CC_IS_PANEL_LIST (self), -1);
|
||||||
|
|
||||||
|
return self->view;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cc_panel_list_set_view (CcPanelList *self,
|
||||||
|
CcPanelListView view)
|
||||||
|
{
|
||||||
|
g_return_if_fail (CC_IS_PANEL_LIST (self));
|
||||||
|
|
||||||
|
if (self->view != view)
|
||||||
|
{
|
||||||
|
GtkWidget *visible_child;
|
||||||
|
gboolean should_crossfade;
|
||||||
|
|
||||||
|
self->previous_view = self->view;
|
||||||
|
self->view = view;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When changing to or from the search view, the animation should
|
||||||
|
* be crossfade. Otherwise, it's the previous-forward movement.
|
||||||
|
*/
|
||||||
|
should_crossfade = view == CC_PANEL_LIST_SEARCH ||
|
||||||
|
self->previous_view == CC_PANEL_LIST_SEARCH;
|
||||||
|
|
||||||
|
gtk_stack_set_transition_type (GTK_STACK (self),
|
||||||
|
should_crossfade ? GTK_STACK_TRANSITION_TYPE_CROSSFADE :
|
||||||
|
GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT);
|
||||||
|
|
||||||
|
visible_child = get_listbox_from_view (self, view);
|
||||||
|
|
||||||
|
gtk_stack_set_visible_child (GTK_STACK (self), visible_child);
|
||||||
|
|
||||||
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VIEW]);
|
||||||
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SEARCH_MODE]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cc_panel_list_add_panel (CcPanelList *self,
|
||||||
|
CcPanelCategory category,
|
||||||
|
const gchar *id,
|
||||||
|
const gchar *title,
|
||||||
|
const gchar *description,
|
||||||
|
const gchar *icon)
|
||||||
|
{
|
||||||
|
GtkWidget *listbox;
|
||||||
|
RowData *data, *search_data;
|
||||||
|
|
||||||
|
g_return_if_fail (CC_IS_PANEL_LIST (self));
|
||||||
|
|
||||||
|
/* Add the panel to the proper listbox */
|
||||||
|
data = row_data_new (category, id, title, description, icon);
|
||||||
|
|
||||||
|
switch (category)
|
||||||
|
{
|
||||||
|
case CC_CATEGORY_DEVICES:
|
||||||
|
listbox = self->devices_listbox;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CC_CATEGORY_DETAILS:
|
||||||
|
listbox = self->details_listbox;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
listbox = self->main_listbox;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_container_add (GTK_CONTAINER (listbox), data->row);
|
||||||
|
|
||||||
|
/* And add to the search listbox too */
|
||||||
|
search_data = row_data_new (category, id, title, description, icon);
|
||||||
|
gtk_container_add (GTK_CONTAINER (self->search_listbox), search_data->row);
|
||||||
|
}
|
67
shell/alt/cc-panel-list.h
Normal file
67
shell/alt/cc-panel-list.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/* cc-panel-list.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 Endless, 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/>.
|
||||||
|
*
|
||||||
|
* Author: Georges Basile Stavracas Neto <gbsneto@gnome.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CC_PANEL_LIST_H
|
||||||
|
#define CC_PANEL_LIST_H
|
||||||
|
|
||||||
|
#include <glib-object.h>
|
||||||
|
|
||||||
|
#include "cc-panel.h"
|
||||||
|
#include "cc-shell-model.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
CC_PANEL_LIST_MAIN,
|
||||||
|
CC_PANEL_LIST_DETAILS,
|
||||||
|
CC_PANEL_LIST_DEVICES,
|
||||||
|
CC_PANEL_LIST_SEARCH
|
||||||
|
} CcPanelListView;
|
||||||
|
|
||||||
|
#define CC_TYPE_PANEL_LIST (cc_panel_list_get_type())
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (CcPanelList, cc_panel_list, CC, PANEL_LIST, GtkStack)
|
||||||
|
|
||||||
|
GtkWidget* cc_panel_list_new (void);
|
||||||
|
|
||||||
|
gboolean cc_panel_list_activate (CcPanelList *self);
|
||||||
|
|
||||||
|
const gchar* cc_panel_list_get_search_query (CcPanelList *self);
|
||||||
|
|
||||||
|
void cc_panel_list_set_search_query (CcPanelList *self,
|
||||||
|
const gchar *search);
|
||||||
|
|
||||||
|
CcPanelListView cc_panel_list_get_view (CcPanelList *self);
|
||||||
|
|
||||||
|
void cc_panel_list_set_view (CcPanelList *self,
|
||||||
|
CcPanelListView view);
|
||||||
|
|
||||||
|
void cc_panel_list_add_panel (CcPanelList *self,
|
||||||
|
CcPanelCategory category,
|
||||||
|
const gchar *id,
|
||||||
|
const gchar *title,
|
||||||
|
const gchar *description,
|
||||||
|
const gchar *icon);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* CC_PANEL_LIST_H */
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
<gresources>
|
<gresources>
|
||||||
<gresource prefix="/org/gnome/ControlCenter/gtk">
|
<gresource prefix="/org/gnome/ControlCenter/gtk">
|
||||||
<file preprocess="xml-stripblanks">help-overlay.ui</file>
|
<file preprocess="xml-stripblanks">help-overlay.ui</file>
|
||||||
|
<file preprocess="xml-stripblanks">panel-list.ui</file>
|
||||||
<file preprocess="xml-stripblanks">window.ui</file>
|
<file preprocess="xml-stripblanks">window.ui</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
</gresources>
|
</gresources>
|
||||||
|
|
209
shell/panel-list.ui
Normal file
209
shell/panel-list.ui
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<requires lib="gtk+" version="3.20"/>
|
||||||
|
<template class="CcPanelList" parent="GtkStack">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="vhomogeneous">False</property>
|
||||||
|
<property name="hhomogeneous">True</property>
|
||||||
|
<property name="transition_type">slide-left-right</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="main_listbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<signal name="row-activated" handler="row_activated_cb" object="CcPanelList" swapped="no" />
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBoxRow" id="devices_row">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="selectable">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="border_width">12</property>
|
||||||
|
<property name="spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">applications-system-symbolic</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="label" translatable="yes">Devices</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">go-next-symbolic</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBoxRow" id="details_row">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="selectable">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="border_width">12</property>
|
||||||
|
<property name="spacing">12</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">applications-system-symbolic</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="label" translatable="yes">Details</property>
|
||||||
|
<property name="xalign">0</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="icon_name">go-next-symbolic</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">main</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="devices_listbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<signal name="row-activated" handler="row_activated_cb" object="CcPanelList" swapped="no" />
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">devices</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="details_listbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<signal name="row-activated" handler="row_activated_cb" object="CcPanelList" swapped="no" />
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">details</property>
|
||||||
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListBox" id="search_listbox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<signal name="row-activated" handler="search_row_activated_cb" object="CcPanelList" swapped="no" />
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="name">search</property>
|
||||||
|
<property name="position">3</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
<object class="GtkBox" id="empty_search_placeholder">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">center</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="border_width">18</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<property name="spacing">6</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkImage">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="pixel_size">72</property>
|
||||||
|
<property name="icon_name">edit-find-symbolic</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">No results found</property>
|
||||||
|
<attributes>
|
||||||
|
<attribute name="weight" value="bold"/>
|
||||||
|
<attribute name="scale" value="1.44"/>
|
||||||
|
</attributes>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="label" translatable="yes">Try a different search</property>
|
||||||
|
<style>
|
||||||
|
<class name="dim-label"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</interface>
|
Loading…
Add table
Add a link
Reference in a new issue