mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-15 14:50:06 +00:00
Merge branch 'selection-filter' into 'master'
Selection filter See merge request GNOME/gtk!2184
This commit is contained in:
commit
1f8e7c8aab
@ -140,6 +140,7 @@
|
|||||||
</gresource>
|
</gresource>
|
||||||
<gresource prefix="/listview_colors">
|
<gresource prefix="/listview_colors">
|
||||||
<file compressed="true">color.names.txt</file>
|
<file compressed="true">color.names.txt</file>
|
||||||
|
<file>listview_colors.css</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
<gresource prefix="/shortcuts">
|
<gresource prefix="/shortcuts">
|
||||||
<file>shortcuts.ui</file>
|
<file>shortcuts.ui</file>
|
||||||
|
@ -627,6 +627,23 @@ setup_listitem_cb (GtkListItemFactory *factory,
|
|||||||
gtk_expression_unref (color_expression);
|
gtk_expression_unref (color_expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup_selection_listitem_cb (GtkListItemFactory *factory,
|
||||||
|
GtkListItem *list_item)
|
||||||
|
{
|
||||||
|
GtkWidget *picture;
|
||||||
|
GtkExpression *color_expression, *expression;
|
||||||
|
|
||||||
|
expression = gtk_constant_expression_new (GTK_TYPE_LIST_ITEM, list_item);
|
||||||
|
color_expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, expression, "item");
|
||||||
|
|
||||||
|
picture = gtk_picture_new ();
|
||||||
|
gtk_widget_set_size_request (picture, 8, 8);
|
||||||
|
gtk_expression_bind (color_expression, picture, "paintable", NULL);
|
||||||
|
|
||||||
|
gtk_list_item_set_child (list_item, picture);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_title (gpointer item,
|
set_title (gpointer item,
|
||||||
const char *title)
|
const char *title)
|
||||||
@ -777,6 +794,47 @@ bind_number_item (GtkSignalListItemFactory *factory,
|
|||||||
g_free (string);
|
g_free (string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_selection_count (GListModel *model,
|
||||||
|
guint position,
|
||||||
|
guint removed,
|
||||||
|
guint added,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
char *text;
|
||||||
|
text = g_strdup_printf ("%u", g_list_model_get_n_items (model));
|
||||||
|
gtk_label_set_label (GTK_LABEL (data), text);
|
||||||
|
g_free (text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
update_selection_average (GListModel *model,
|
||||||
|
guint position,
|
||||||
|
guint removed,
|
||||||
|
guint added,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
guint n = g_list_model_get_n_items (model);
|
||||||
|
GdkRGBA c = { 0, 0, 0, 1 };
|
||||||
|
guint i;
|
||||||
|
GtkColor *color;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
color = g_list_model_get_item (model, i);
|
||||||
|
|
||||||
|
c.red += color->color.red;
|
||||||
|
c.green += color->color.green;
|
||||||
|
c.blue += color->color.blue;
|
||||||
|
|
||||||
|
g_object_unref (color);
|
||||||
|
}
|
||||||
|
|
||||||
|
color = gtk_color_new ("", c.red / n, c.green / n, c.blue / n);
|
||||||
|
gtk_picture_set_paintable (GTK_PICTURE (data), GDK_PAINTABLE (color));
|
||||||
|
g_object_unref (color);
|
||||||
|
}
|
||||||
|
|
||||||
static GtkWidget *window = NULL;
|
static GtkWidget *window = NULL;
|
||||||
|
|
||||||
GtkWidget *
|
GtkWidget *
|
||||||
@ -797,6 +855,22 @@ do_listview_colors (GtkWidget *do_widget)
|
|||||||
PangoAttrList *attrs;
|
PangoAttrList *attrs;
|
||||||
char *string;
|
char *string;
|
||||||
guint len;
|
guint len;
|
||||||
|
GtkWidget *selection_view;
|
||||||
|
GListModel *selection_filter;
|
||||||
|
GListModel *no_selection;
|
||||||
|
GtkWidget *grid;
|
||||||
|
GtkWidget *selection_size_label;
|
||||||
|
GtkWidget *selection_average_picture;
|
||||||
|
GtkWidget *selection_info_toggle;
|
||||||
|
GtkWidget *selection_info_revealer;
|
||||||
|
GtkCssProvider *provider;
|
||||||
|
|
||||||
|
provider = gtk_css_provider_new ();
|
||||||
|
gtk_css_provider_load_from_resource (provider, "/listview_colors/listview_colors.css");
|
||||||
|
gtk_style_context_add_provider_for_display (gdk_display_get_default (),
|
||||||
|
GTK_STYLE_PROVIDER (provider),
|
||||||
|
800);
|
||||||
|
g_object_unref (provider);
|
||||||
|
|
||||||
window = gtk_window_new ();
|
window = gtk_window_new ();
|
||||||
gtk_window_set_title (GTK_WINDOW (window), "Colors");
|
gtk_window_set_title (GTK_WINDOW (window), "Colors");
|
||||||
@ -809,14 +883,85 @@ do_listview_colors (GtkWidget *do_widget)
|
|||||||
gtk_widget_get_display (do_widget));
|
gtk_widget_get_display (do_widget));
|
||||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer*)&window);
|
g_object_add_weak_pointer (G_OBJECT (window), (gpointer*)&window);
|
||||||
|
|
||||||
|
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||||
|
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||||
|
|
||||||
|
selection_info_revealer = gtk_revealer_new ();
|
||||||
|
gtk_box_append (GTK_BOX (box), selection_info_revealer);
|
||||||
|
|
||||||
|
grid = gtk_grid_new ();
|
||||||
|
gtk_revealer_set_child (GTK_REVEALER (selection_info_revealer), grid);
|
||||||
|
gtk_widget_set_margin_start (grid, 10);
|
||||||
|
gtk_widget_set_margin_end (grid, 10);
|
||||||
|
gtk_widget_set_margin_top (grid, 10);
|
||||||
|
gtk_widget_set_margin_bottom (grid, 10);
|
||||||
|
gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
|
||||||
|
gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
|
||||||
|
|
||||||
|
label = gtk_label_new ("Selection");
|
||||||
|
gtk_widget_set_hexpand (label, TRUE);
|
||||||
|
gtk_widget_add_css_class (label, "title-3");
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 5, 1);
|
||||||
|
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Size:"), 0, 2, 1, 1);
|
||||||
|
|
||||||
|
selection_size_label = gtk_label_new ("0");
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), selection_size_label, 1, 2, 1, 1);
|
||||||
|
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), gtk_label_new ("Average:"), 2, 2, 1, 1);
|
||||||
|
|
||||||
|
selection_average_picture = gtk_picture_new ();
|
||||||
|
gtk_widget_set_size_request (selection_average_picture, 32, 32);
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), selection_average_picture, 3, 2, 1, 1);
|
||||||
|
|
||||||
|
label = gtk_label_new ("");
|
||||||
|
gtk_widget_set_hexpand (label, TRUE);
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), label, 4, 2, 1, 1);
|
||||||
|
|
||||||
sw = gtk_scrolled_window_new ();
|
sw = gtk_scrolled_window_new ();
|
||||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
gtk_widget_set_hexpand (sw, TRUE);
|
||||||
|
|
||||||
|
gtk_grid_attach (GTK_GRID (grid), sw, 0, 1, 5, 1);
|
||||||
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
|
||||||
|
GTK_POLICY_NEVER,
|
||||||
|
GTK_POLICY_AUTOMATIC);
|
||||||
|
|
||||||
|
factory = gtk_signal_list_item_factory_new ();
|
||||||
|
g_signal_connect (factory, "setup", G_CALLBACK (setup_selection_listitem_cb), NULL);
|
||||||
|
selection_view = gtk_grid_view_new_with_factory (factory);
|
||||||
|
gtk_widget_add_css_class (selection_view, "compact");
|
||||||
|
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (selection_view), 200);
|
||||||
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), selection_view);
|
||||||
|
|
||||||
|
sw = gtk_scrolled_window_new ();
|
||||||
|
gtk_box_append (GTK_BOX (box), sw);
|
||||||
|
|
||||||
gridview = create_color_grid ();
|
gridview = create_color_grid ();
|
||||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), gridview);
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), gridview);
|
||||||
|
gtk_widget_set_hexpand (sw, TRUE);
|
||||||
|
gtk_widget_set_vexpand (sw, TRUE);
|
||||||
model = gtk_grid_view_get_model (GTK_GRID_VIEW (gridview));
|
model = gtk_grid_view_get_model (GTK_GRID_VIEW (gridview));
|
||||||
|
|
||||||
|
selection_filter = G_LIST_MODEL (gtk_selection_filter_model_new (GTK_SELECTION_MODEL (model)));
|
||||||
|
g_signal_connect (selection_filter, "items-changed", G_CALLBACK (update_selection_count), selection_size_label);
|
||||||
|
g_signal_connect (selection_filter, "items-changed", G_CALLBACK (update_selection_average), selection_average_picture);
|
||||||
|
|
||||||
|
no_selection = G_LIST_MODEL (gtk_no_selection_new (selection_filter));
|
||||||
|
gtk_grid_view_set_model (GTK_GRID_VIEW (selection_view), no_selection);
|
||||||
|
g_object_unref (selection_filter);
|
||||||
|
g_object_unref (no_selection);
|
||||||
|
|
||||||
g_object_get (model, "model", &model, NULL);
|
g_object_get (model, "model", &model, NULL);
|
||||||
|
|
||||||
|
selection_info_toggle = gtk_toggle_button_new ();
|
||||||
|
gtk_button_set_icon_name (GTK_BUTTON (selection_info_toggle), "emblem-important-symbolic");
|
||||||
|
gtk_widget_set_tooltip_text (selection_info_toggle, "Show selection info");
|
||||||
|
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), selection_info_toggle);
|
||||||
|
|
||||||
|
g_object_bind_property (selection_info_toggle, "active",
|
||||||
|
selection_info_revealer, "reveal-child",
|
||||||
|
G_BINDING_DEFAULT);
|
||||||
|
|
||||||
button = gtk_button_new_with_mnemonic ("_Refill");
|
button = gtk_button_new_with_mnemonic ("_Refill");
|
||||||
g_signal_connect (button, "clicked",
|
g_signal_connect (button, "clicked",
|
||||||
G_CALLBACK (refill),
|
G_CALLBACK (refill),
|
||||||
|
3
demos/gtk-demo/listview_colors.css
Normal file
3
demos/gtk-demo/listview_colors.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.view.compact > child {
|
||||||
|
padding: 1px;
|
||||||
|
}
|
@ -74,6 +74,7 @@
|
|||||||
<xi:include href="xml/gtksingleselection.xml" />
|
<xi:include href="xml/gtksingleselection.xml" />
|
||||||
<xi:include href="xml/gtkmultiselection.xml" />
|
<xi:include href="xml/gtkmultiselection.xml" />
|
||||||
</section>
|
</section>
|
||||||
|
<xi:include href="xml/gtkselectionfiltermodel.xml" />
|
||||||
<xi:include href="xml/gtkbookmarklist.xml" />
|
<xi:include href="xml/gtkbookmarklist.xml" />
|
||||||
<xi:include href="xml/gtkdirectorylist.xml" />
|
<xi:include href="xml/gtkdirectorylist.xml" />
|
||||||
<xi:include href="xml/gtkstringlist.xml" />
|
<xi:include href="xml/gtkstringlist.xml" />
|
||||||
|
@ -355,6 +355,9 @@ gtk_bitset_is_empty
|
|||||||
gtk_bitset_equals
|
gtk_bitset_equals
|
||||||
gtk_bitset_get_minimum
|
gtk_bitset_get_minimum
|
||||||
gtk_bitset_get_maximum
|
gtk_bitset_get_maximum
|
||||||
|
gtk_bitset_get_size
|
||||||
|
gtk_bitset_get_size_in_range
|
||||||
|
gtk_bitset_get_nth
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
gtk_bitset_remove_all
|
gtk_bitset_remove_all
|
||||||
gtk_bitset_add
|
gtk_bitset_add
|
||||||
@ -7610,3 +7613,13 @@ gtk_string_list_get_string
|
|||||||
GtkStringObject
|
GtkStringObject
|
||||||
gtk_string_object_get_string
|
gtk_string_object_get_string
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
|
<SECTION>
|
||||||
|
<FILE>gtkselectionfiltermodel</FILE>
|
||||||
|
<TITLE>GtkSelectionFilterModel</TITLE>
|
||||||
|
GtkSelectionFilterModel
|
||||||
|
gtk_selection_filter_model_new
|
||||||
|
gtk_selection_filter_model_new_for_type
|
||||||
|
gtk_selection_filter_model_set_model
|
||||||
|
gtk_selection_filter_model_get_model
|
||||||
|
</SECTION>
|
||||||
|
@ -184,6 +184,7 @@ gtk_scrollbar_get_type
|
|||||||
gtk_scrolled_window_get_type
|
gtk_scrolled_window_get_type
|
||||||
gtk_search_bar_get_type
|
gtk_search_bar_get_type
|
||||||
gtk_search_entry_get_type
|
gtk_search_entry_get_type
|
||||||
|
gtk_selection_filter_model_get_type
|
||||||
gtk_selection_model_get_type
|
gtk_selection_model_get_type
|
||||||
gtk_separator_get_type
|
gtk_separator_get_type
|
||||||
gtk_settings_get_type
|
gtk_settings_get_type
|
||||||
|
@ -213,6 +213,7 @@
|
|||||||
#include <gtk/gtkscrolledwindow.h>
|
#include <gtk/gtkscrolledwindow.h>
|
||||||
#include <gtk/gtksearchbar.h>
|
#include <gtk/gtksearchbar.h>
|
||||||
#include <gtk/gtksearchentry.h>
|
#include <gtk/gtksearchentry.h>
|
||||||
|
#include <gtk/gtkselectionfiltermodel.h>
|
||||||
#include <gtk/gtkselectionmodel.h>
|
#include <gtk/gtkselectionmodel.h>
|
||||||
#include <gtk/gtkseparator.h>
|
#include <gtk/gtkseparator.h>
|
||||||
#include <gtk/gtksettings.h>
|
#include <gtk/gtksettings.h>
|
||||||
|
@ -193,6 +193,76 @@ gtk_bitset_get_maximum (const GtkBitset *self)
|
|||||||
return roaring_bitmap_maximum (&self->roaring);
|
return roaring_bitmap_maximum (&self->roaring);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_bitset_get_size:
|
||||||
|
* @self: a #GtkBitSet
|
||||||
|
*
|
||||||
|
* Gets the number of values that were added to the set.
|
||||||
|
* For example, if the set is empty, 0 is returned.
|
||||||
|
*
|
||||||
|
* Note that this function returns a #guint64, because when all values are
|
||||||
|
* set, the return value is #G_MAXUINT + 1. Unless you are sure this cannot
|
||||||
|
* happen (it can't with #GListModel), be sure to use a 64bit type.
|
||||||
|
*
|
||||||
|
* Returns: The number of values in the set.
|
||||||
|
**/
|
||||||
|
guint64
|
||||||
|
gtk_bitset_get_size (const GtkBitset *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (self != NULL, 0);
|
||||||
|
|
||||||
|
return roaring_bitmap_get_cardinality (&self->roaring);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_bitset_get_size_in_range:
|
||||||
|
* @self: a #GtkBitSet
|
||||||
|
* @first: the first element to include
|
||||||
|
* @last: the last element to include
|
||||||
|
*
|
||||||
|
* Gets the number of values that are part of the set from @first to @last
|
||||||
|
* (inclusive).
|
||||||
|
*
|
||||||
|
* Note that this function returns a #guint64, because when all values are
|
||||||
|
* set, the return value is #G_MAXUINT + 1. Unless you are sure this cannot
|
||||||
|
* happen (it can't with #GListModel), be sure to use a 64bit type.
|
||||||
|
*
|
||||||
|
* Returns: The number of values in the set from @first to @last.
|
||||||
|
**/
|
||||||
|
guint64
|
||||||
|
gtk_bitset_get_size_in_range (const GtkBitset *self,
|
||||||
|
guint first,
|
||||||
|
guint last)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (self != NULL, 0);
|
||||||
|
g_return_val_if_fail (last >= first, 0);
|
||||||
|
|
||||||
|
return roaring_bitmap_range_cardinality (&self->roaring, first, ((uint64_t) last) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_bitset_get_nth:
|
||||||
|
* @self: a #GtkBitset
|
||||||
|
* @nth: index of the item to get
|
||||||
|
*
|
||||||
|
* Returns the value of the @nth item in self.
|
||||||
|
*
|
||||||
|
* If @nth is >= the size of @self, 0 is returned.
|
||||||
|
*
|
||||||
|
* Returns: the value of the @nth item in @self
|
||||||
|
**/
|
||||||
|
guint
|
||||||
|
gtk_bitset_get_nth (const GtkBitset *self,
|
||||||
|
guint nth)
|
||||||
|
{
|
||||||
|
uint32_t result;
|
||||||
|
|
||||||
|
if (!roaring_bitmap_select (&self->roaring, nth, &result))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gtk_bitset_new_empty:
|
* gtk_bitset_new_empty:
|
||||||
*
|
*
|
||||||
|
@ -48,6 +48,15 @@ GDK_AVAILABLE_IN_ALL
|
|||||||
gboolean gtk_bitset_equals (const GtkBitset *self,
|
gboolean gtk_bitset_equals (const GtkBitset *self,
|
||||||
const GtkBitset *other);
|
const GtkBitset *other);
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
guint64 gtk_bitset_get_size (const GtkBitset *self);
|
||||||
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
guint64 gtk_bitset_get_size_in_range (const GtkBitset *self,
|
||||||
|
guint first,
|
||||||
|
guint last);
|
||||||
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
guint gtk_bitset_get_nth (const GtkBitset *self,
|
||||||
|
guint nth);
|
||||||
|
GDK_AVAILABLE_IN_ALL
|
||||||
guint gtk_bitset_get_minimum (const GtkBitset *self);
|
guint gtk_bitset_get_minimum (const GtkBitset *self);
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
guint gtk_bitset_get_maximum (const GtkBitset *self);
|
guint gtk_bitset_get_maximum (const GtkBitset *self);
|
||||||
|
@ -684,7 +684,7 @@ gtk_filter_list_model_class_init (GtkFilterListModelClass *class)
|
|||||||
P_("Model"),
|
P_("Model"),
|
||||||
P_("The model being filtered"),
|
P_("The model being filtered"),
|
||||||
G_TYPE_LIST_MODEL,
|
G_TYPE_LIST_MODEL,
|
||||||
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||||
|
|
||||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||||
}
|
}
|
||||||
|
376
gtk/gtkselectionfiltermodel.c
Normal file
376
gtk/gtkselectionfiltermodel.c
Normal file
@ -0,0 +1,376 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2020 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Authors: Matthias Clasen
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "gtkselectionfiltermodel.h"
|
||||||
|
#include "gtkbitset.h"
|
||||||
|
|
||||||
|
#include "gtkintl.h"
|
||||||
|
#include "gtkprivate.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTION:gtkselectionfiltermodel
|
||||||
|
* @title: GtkSelectionFilterModel
|
||||||
|
* @short_description: A list model that turns a selection in a model
|
||||||
|
* @see_also: #GtkSelectionModel
|
||||||
|
*
|
||||||
|
* #GtkSelectionFilterModel is a list model that presents the
|
||||||
|
* selected items in a #GtkSelectionModel as its own list model.
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PROP_0,
|
||||||
|
PROP_ITEM_TYPE,
|
||||||
|
PROP_MODEL,
|
||||||
|
NUM_PROPERTIES
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GtkSelectionFilterModel
|
||||||
|
{
|
||||||
|
GObject parent_instance;
|
||||||
|
|
||||||
|
GType item_type;
|
||||||
|
GtkSelectionModel *model;
|
||||||
|
GtkBitset *selection;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _GtkSelectionFilterModelClass
|
||||||
|
{
|
||||||
|
GObjectClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
|
||||||
|
|
||||||
|
static GType
|
||||||
|
gtk_selection_filter_model_get_item_type (GListModel *list)
|
||||||
|
{
|
||||||
|
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (list);
|
||||||
|
|
||||||
|
return self->item_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint
|
||||||
|
gtk_selection_filter_model_get_n_items (GListModel *list)
|
||||||
|
{
|
||||||
|
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (list);
|
||||||
|
|
||||||
|
if (self->selection)
|
||||||
|
return gtk_bitset_get_size (self->selection);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
gtk_selection_filter_model_get_item (GListModel *list,
|
||||||
|
guint position)
|
||||||
|
{
|
||||||
|
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (list);
|
||||||
|
|
||||||
|
position = gtk_bitset_get_nth (self->selection, position);
|
||||||
|
|
||||||
|
return g_list_model_get_item (G_LIST_MODEL (self->model), position);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_selection_filter_model_list_model_init (GListModelInterface *iface)
|
||||||
|
{
|
||||||
|
iface->get_item_type = gtk_selection_filter_model_get_item_type;
|
||||||
|
iface->get_n_items = gtk_selection_filter_model_get_n_items;
|
||||||
|
iface->get_item = gtk_selection_filter_model_get_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
G_DEFINE_TYPE_WITH_CODE (GtkSelectionFilterModel, gtk_selection_filter_model, G_TYPE_OBJECT,
|
||||||
|
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_selection_filter_model_list_model_init))
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_selection_filter_model_items_changed_cb (GListModel *model,
|
||||||
|
guint position,
|
||||||
|
guint removed,
|
||||||
|
guint added,
|
||||||
|
GtkSelectionFilterModel *self)
|
||||||
|
{
|
||||||
|
GtkBitset *selection;
|
||||||
|
guint sel_position;
|
||||||
|
guint sel_removed;
|
||||||
|
guint sel_added;
|
||||||
|
|
||||||
|
selection = gtk_selection_model_get_selection (self->model);
|
||||||
|
|
||||||
|
sel_position = gtk_bitset_get_size_in_range (self->selection, 0, position - 1);
|
||||||
|
sel_removed = gtk_bitset_get_size_in_range (self->selection, position, position + removed);
|
||||||
|
sel_added = gtk_bitset_get_size_in_range (selection, position, position + added);
|
||||||
|
|
||||||
|
gtk_bitset_unref (self->selection);
|
||||||
|
self->selection = gtk_bitset_copy (selection);
|
||||||
|
|
||||||
|
gtk_bitset_unref (selection);
|
||||||
|
|
||||||
|
if (sel_removed > 0 || sel_added > 0)
|
||||||
|
g_list_model_items_changed (G_LIST_MODEL (self), sel_position, sel_removed, sel_added);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_selection_filter_model_selection_changed_cb (GListModel *model,
|
||||||
|
guint position,
|
||||||
|
guint n_items,
|
||||||
|
GtkSelectionFilterModel *self)
|
||||||
|
{
|
||||||
|
GtkBitset *selection;
|
||||||
|
guint sel_position;
|
||||||
|
guint sel_removed;
|
||||||
|
guint sel_added;
|
||||||
|
|
||||||
|
selection = gtk_selection_model_get_selection (self->model);
|
||||||
|
|
||||||
|
sel_position = gtk_bitset_get_size_in_range (self->selection, 0, position - 1);
|
||||||
|
sel_removed = gtk_bitset_get_size_in_range (self->selection, position, position + n_items);
|
||||||
|
sel_added = gtk_bitset_get_size_in_range (selection, position, position + n_items);
|
||||||
|
|
||||||
|
gtk_bitset_unref (self->selection);
|
||||||
|
self->selection = gtk_bitset_copy (selection);
|
||||||
|
|
||||||
|
gtk_bitset_unref (selection);
|
||||||
|
|
||||||
|
if (sel_removed > 0 || sel_added > 0)
|
||||||
|
g_list_model_items_changed (G_LIST_MODEL (self), sel_position, sel_removed, sel_added);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_selection_filter_model_set_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
const GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_ITEM_TYPE:
|
||||||
|
self->item_type = g_value_get_gtype (value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_MODEL:
|
||||||
|
gtk_selection_filter_model_set_model (self, g_value_get_object (value));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_selection_filter_model_get_property (GObject *object,
|
||||||
|
guint prop_id,
|
||||||
|
GValue *value,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (object);
|
||||||
|
|
||||||
|
switch (prop_id)
|
||||||
|
{
|
||||||
|
case PROP_ITEM_TYPE:
|
||||||
|
g_value_set_gtype (value, self->item_type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PROP_MODEL:
|
||||||
|
g_value_set_object (value, self->model);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_selection_filter_model_clear_model (GtkSelectionFilterModel *self)
|
||||||
|
{
|
||||||
|
if (self->model == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_signal_handlers_disconnect_by_func (self->model, gtk_selection_filter_model_items_changed_cb, self);
|
||||||
|
g_signal_handlers_disconnect_by_func (self->model, gtk_selection_filter_model_selection_changed_cb, self);
|
||||||
|
|
||||||
|
g_clear_object (&self->model);
|
||||||
|
g_clear_pointer (&self->selection, gtk_bitset_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_selection_filter_model_dispose (GObject *object)
|
||||||
|
{
|
||||||
|
GtkSelectionFilterModel *self = GTK_SELECTION_FILTER_MODEL (object);
|
||||||
|
|
||||||
|
gtk_selection_filter_model_clear_model (self);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (gtk_selection_filter_model_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_selection_filter_model_class_init (GtkSelectionFilterModelClass *class)
|
||||||
|
{
|
||||||
|
GObjectClass *gobject_class = G_OBJECT_CLASS (class);
|
||||||
|
|
||||||
|
gobject_class->set_property = gtk_selection_filter_model_set_property;
|
||||||
|
gobject_class->get_property = gtk_selection_filter_model_get_property;
|
||||||
|
gobject_class->dispose = gtk_selection_filter_model_dispose;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GtkSelectionFilterModel:item-type:
|
||||||
|
*
|
||||||
|
* The #GType for elements of this object
|
||||||
|
*/
|
||||||
|
properties[PROP_ITEM_TYPE] =
|
||||||
|
g_param_spec_gtype ("item-type",
|
||||||
|
P_("Item type"),
|
||||||
|
P_("The type of elements of this object"),
|
||||||
|
G_TYPE_OBJECT,
|
||||||
|
GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GtkSelectionFilterModel:model:
|
||||||
|
*
|
||||||
|
* The model being filtered
|
||||||
|
*/
|
||||||
|
properties[PROP_MODEL] =
|
||||||
|
g_param_spec_object ("model",
|
||||||
|
P_("Model"),
|
||||||
|
P_("The model being filtered"),
|
||||||
|
GTK_TYPE_SELECTION_MODEL,
|
||||||
|
GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||||
|
|
||||||
|
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_selection_filter_model_init (GtkSelectionFilterModel *self)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_selection_filter_model_new:
|
||||||
|
* @model: the selection model to filter
|
||||||
|
*
|
||||||
|
* Creates a new #GtkSelectionFilterModel that will include the
|
||||||
|
* selected items from the underlying selection model.
|
||||||
|
*
|
||||||
|
* Returns: a new #GtkSelectionFilterModel
|
||||||
|
**/
|
||||||
|
GtkSelectionFilterModel *
|
||||||
|
gtk_selection_filter_model_new (GtkSelectionModel *model)
|
||||||
|
{
|
||||||
|
GtkSelectionFilterModel *result;
|
||||||
|
|
||||||
|
g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), NULL);
|
||||||
|
|
||||||
|
result = g_object_new (GTK_TYPE_SELECTION_FILTER_MODEL,
|
||||||
|
"item-type", g_list_model_get_item_type (G_LIST_MODEL (model)),
|
||||||
|
"model", model,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_selection_filter_model_new_for_type:
|
||||||
|
* @item_type: the type of the items that will be returned
|
||||||
|
*
|
||||||
|
* Creates a new empty selection filter model set up to return items
|
||||||
|
* of type @item_type. It is up to the application to set a proper
|
||||||
|
* selection model to ensure the item type is matched.
|
||||||
|
*
|
||||||
|
* Returns: a new #GtkSelectionFilterModel
|
||||||
|
**/
|
||||||
|
GtkSelectionFilterModel *
|
||||||
|
gtk_selection_filter_model_new_for_type (GType item_type)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (g_type_is_a (item_type, G_TYPE_OBJECT), NULL);
|
||||||
|
|
||||||
|
return g_object_new (GTK_TYPE_SELECTION_FILTER_MODEL,
|
||||||
|
"item-type", item_type,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_selection_filter_model_set_model:
|
||||||
|
* @self: a #GtkSelectionFilterModel
|
||||||
|
* @model: (allow-none): The model to be filtered
|
||||||
|
*
|
||||||
|
* Sets the model to be filtered.
|
||||||
|
*
|
||||||
|
* Note that GTK makes no effort to ensure that @model conforms to
|
||||||
|
* the item type of @self. It assumes that the caller knows what they
|
||||||
|
* are doing and have set up an appropriate filter to ensure that item
|
||||||
|
* types match.
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
gtk_selection_filter_model_set_model (GtkSelectionFilterModel *self,
|
||||||
|
GtkSelectionModel *model)
|
||||||
|
{
|
||||||
|
guint removed, added;
|
||||||
|
|
||||||
|
g_return_if_fail (GTK_IS_SELECTION_FILTER_MODEL (self));
|
||||||
|
g_return_if_fail (model == NULL || GTK_IS_SELECTION_MODEL (model));
|
||||||
|
g_return_if_fail (model == NULL || g_type_is_a (g_list_model_get_item_type (G_LIST_MODEL (model)),
|
||||||
|
self->item_type));
|
||||||
|
|
||||||
|
if (self->model == model)
|
||||||
|
return;
|
||||||
|
|
||||||
|
removed = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||||
|
gtk_selection_filter_model_clear_model (self);
|
||||||
|
|
||||||
|
if (model)
|
||||||
|
{
|
||||||
|
GtkBitset *selection;
|
||||||
|
|
||||||
|
self->model = g_object_ref (model);
|
||||||
|
|
||||||
|
selection = gtk_selection_model_get_selection (self->model);
|
||||||
|
self->selection = gtk_bitset_copy (selection);
|
||||||
|
gtk_bitset_unref (selection);
|
||||||
|
|
||||||
|
g_signal_connect (model, "items-changed", G_CALLBACK (gtk_selection_filter_model_items_changed_cb), self);
|
||||||
|
g_signal_connect (model, "selection-changed", G_CALLBACK (gtk_selection_filter_model_selection_changed_cb), self);
|
||||||
|
}
|
||||||
|
|
||||||
|
added = g_list_model_get_n_items (G_LIST_MODEL (self));
|
||||||
|
|
||||||
|
if (removed > 0 || added > 0)
|
||||||
|
g_list_model_items_changed (G_LIST_MODEL (self), 0, removed, added);
|
||||||
|
|
||||||
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_selection_filter_model_get_model:
|
||||||
|
* @self: a #GtkSelectionFilterModel
|
||||||
|
*
|
||||||
|
* Gets the model currently filtered or %NULL if none.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer none): The model that gets filtered
|
||||||
|
**/
|
||||||
|
GtkSelectionModel *
|
||||||
|
gtk_selection_filter_model_get_model (GtkSelectionFilterModel *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GTK_IS_SELECTION_FILTER_MODEL (self), NULL);
|
||||||
|
|
||||||
|
return self->model;
|
||||||
|
}
|
52
gtk/gtkselectionfiltermodel.h
Normal file
52
gtk/gtkselectionfiltermodel.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2020 Red Hat, Inc.
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library 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
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* Authors: Matthias Clasen
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __GTK_SELECTION_FILTER_MODEL_H__
|
||||||
|
#define __GTK_SELECTION_FILTER_MODEL_H__
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||||
|
#error "Only <gtk/gtk.h> can be included directly."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <gtk/gtkselectionmodel.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
#define GTK_TYPE_SELECTION_FILTER_MODEL (gtk_selection_filter_model_get_type ())
|
||||||
|
|
||||||
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
G_DECLARE_FINAL_TYPE (GtkSelectionFilterModel, gtk_selection_filter_model, GTK, SELECTION_FILTER_MODEL, GObject)
|
||||||
|
|
||||||
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
GtkSelectionFilterModel * gtk_selection_filter_model_new (GtkSelectionModel *model);
|
||||||
|
|
||||||
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
GtkSelectionFilterModel * gtk_selection_filter_model_new_for_type (GType item_type);
|
||||||
|
|
||||||
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
void gtk_selection_filter_model_set_model (GtkSelectionFilterModel *self,
|
||||||
|
GtkSelectionModel *model);
|
||||||
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
GtkSelectionModel * gtk_selection_filter_model_get_model (GtkSelectionFilterModel *self);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif /* __GTK_SELECTION_FILTER_MODEL_H__ */
|
@ -348,6 +348,7 @@ gtk_public_sources = files([
|
|||||||
'gtkscrolledwindow.c',
|
'gtkscrolledwindow.c',
|
||||||
'gtksearchbar.c',
|
'gtksearchbar.c',
|
||||||
'gtksearchentry.c',
|
'gtksearchentry.c',
|
||||||
|
'gtkselectionfiltermodel.c',
|
||||||
'gtkselectionmodel.c',
|
'gtkselectionmodel.c',
|
||||||
'gtkseparator.c',
|
'gtkseparator.c',
|
||||||
'gtksettings.c',
|
'gtksettings.c',
|
||||||
@ -617,6 +618,7 @@ gtk_public_headers = files([
|
|||||||
'gtkscrolledwindow.h',
|
'gtkscrolledwindow.h',
|
||||||
'gtksearchbar.h',
|
'gtksearchbar.h',
|
||||||
'gtksearchentry.h',
|
'gtksearchentry.h',
|
||||||
|
'gtkselectionfiltermodel.h',
|
||||||
'gtkselectionmodel.h',
|
'gtkselectionmodel.h',
|
||||||
'gtkseparator.h',
|
'gtkseparator.h',
|
||||||
'gtksettings.h',
|
'gtksettings.h',
|
||||||
|
Loading…
Reference in New Issue
Block a user