Compare commits
71 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 543cf3f907 | |||
| e904668cb1 | |||
| 15d494ddc4 | |||
| 92729a9551 | |||
| e98f70d6d5 | |||
| 84b6d14ad2 | |||
| 3f5e859795 | |||
| 780a9c1a1f | |||
| b9c3a15d60 | |||
| 076a40c9bb | |||
| d8ab29a431 | |||
| ea0b36b330 | |||
| c8157480ce | |||
| 3eb0f92705 | |||
| 10ac5cd977 | |||
| d41fe03b73 | |||
| bf8856e3fb | |||
| 4a46e8331e | |||
| 241b20c39f | |||
| 151cd0a296 | |||
| 05b6becd2f | |||
| a2d6f1f0cb | |||
| d2af96f9c8 | |||
| b1ab5e187d | |||
| fd51444967 | |||
| 843999265b | |||
| 8dfbef5e6f | |||
| 0b9a3fc160 | |||
| 79105962a7 | |||
| cc878160bd | |||
| 382153e82d | |||
| e195341e30 | |||
| c6c8263704 | |||
| ed02bea20d | |||
| f89a1b05fe | |||
| af65b7e6d7 | |||
| 1995ad6d63 | |||
| 83c0937a46 | |||
| f5cc2c0d20 | |||
| 931d68bc92 | |||
| 06946c35d3 | |||
| cbe81fd443 | |||
| 173e919d2a | |||
| 73fdb8f7b0 | |||
| 8e0ba37866 | |||
| 8780f50e7e | |||
| 06dc357ea0 | |||
| fb587cb529 | |||
| a026677849 | |||
| 1c389b1f24 | |||
| 55b9aa0309 | |||
| 2d5cf2b4c4 | |||
| 4877bb5b5c | |||
| b9269d5644 | |||
| 1a4723988e | |||
| 93353888ca | |||
| c3a90b76d0 | |||
| 43e5ca9a1b | |||
| c5829bd0e2 | |||
| 2a9d2cc7e9 | |||
| 0d9873d8bc | |||
| 23bc38ed06 | |||
| 42d26b4b05 | |||
| 04700789e1 | |||
| e23baa59f0 | |||
| e8e28b61db | |||
| b766707f28 | |||
| 0787f262a0 | |||
| d833f4a632 | |||
| ce1e364ab8 | |||
| adb5b299c9 |
@@ -27,18 +27,6 @@
|
||||
/* Define to 1 if you have the `dcgettext' function. */
|
||||
#mesondefine HAVE_DCGETTEXT
|
||||
|
||||
/* Define to 1 if you have the declaration of `isinf', and to 0 if you don't.
|
||||
*/
|
||||
#mesondefine HAVE_DECL_ISINF
|
||||
|
||||
/* Define to 1 if you have the declaration of `isnan', and to 0 if you don't.
|
||||
*/
|
||||
#mesondefine HAVE_DECL_ISNAN
|
||||
|
||||
/* Define to 1 if you have the declaration of `isnanf', and to 0 if you don't.
|
||||
*/
|
||||
#mesondefine HAVE_DECL_ISNANF
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#mesondefine HAVE_DLFCN_H
|
||||
|
||||
@@ -84,9 +72,6 @@
|
||||
/* Define to 1 if you have a working `mmap' system call. */
|
||||
#mesondefine HAVE_MMAP
|
||||
|
||||
/* Define to 1 if you have the `nearbyint' function. */
|
||||
#mesondefine HAVE_NEARBYINT
|
||||
|
||||
/* Define to 1 if you have the `posix_fallocate' function. */
|
||||
#mesondefine HAVE_POSIX_FALLOCATE
|
||||
|
||||
@@ -96,21 +81,9 @@
|
||||
/* Have the Xrandr 1.5 extension library */
|
||||
#mesondefine HAVE_RANDR15
|
||||
|
||||
/* Define to 1 if you have the `rint' function. */
|
||||
#mesondefine HAVE_RINT
|
||||
|
||||
/* Define to 1 if you have the `round' function. */
|
||||
#mesondefine HAVE_ROUND
|
||||
|
||||
/* Define to 1 if you have the `sincos' function. */
|
||||
#mesondefine HAVE_SINCOS
|
||||
|
||||
/* Define to 1 if you have the `log2` function */
|
||||
#mesondefine HAVE_LOG2
|
||||
|
||||
/* Define to 1 if you ahve the `exp2` function */
|
||||
#mesondefine HAVE_EXP2
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#mesondefine HAVE_STDINT_H
|
||||
|
||||
|
||||
@@ -3,8 +3,15 @@
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="label" bind-source="GtkListItem" bind-property="position"></property>
|
||||
<property name="margin">6</property>
|
||||
<binding name="label">
|
||||
<lookup name="title" type="GtkAward">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<property name="margin-start">6</property>
|
||||
<property name="margin-end">6</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
|
||||
@@ -218,7 +218,6 @@
|
||||
<file>infobar.c</file>
|
||||
<file>links.c</file>
|
||||
<file>listbox.c</file>
|
||||
<file>listview_applauncher.c</file>
|
||||
<file>listview_colors.c</file>
|
||||
<file>listview_clocks.c</file>
|
||||
<file>listview_filebrowser.c</file>
|
||||
|
||||
@@ -12,7 +12,7 @@ static GtkWidget *window = NULL;
|
||||
static GtkWidget *scrolledwindow;
|
||||
static int selected;
|
||||
|
||||
#define N_WIDGET_TYPES 4
|
||||
#define N_WIDGET_TYPES 6
|
||||
|
||||
|
||||
static int hincrement = 5;
|
||||
@@ -64,6 +64,7 @@ populate_icons (void)
|
||||
gtk_grid_attach (GTK_GRID (grid), create_icon (), left, top, 1, 1);
|
||||
|
||||
hincrement = 0;
|
||||
vincrement = 5;
|
||||
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
|
||||
GTK_POLICY_NEVER,
|
||||
@@ -100,6 +101,7 @@ populate_text (gboolean hilight)
|
||||
gtk_text_view_set_buffer (GTK_TEXT_VIEW (textview), buffer);
|
||||
|
||||
hincrement = 0;
|
||||
vincrement = 5;
|
||||
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
|
||||
GTK_POLICY_NEVER,
|
||||
@@ -124,6 +126,7 @@ populate_image (void)
|
||||
gtk_picture_set_can_shrink (GTK_PICTURE (image), FALSE);
|
||||
|
||||
hincrement = 5;
|
||||
vincrement = 5;
|
||||
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
@@ -131,6 +134,42 @@ populate_image (void)
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), image);
|
||||
}
|
||||
|
||||
extern GtkWidget *create_weather_view (void);
|
||||
|
||||
static void
|
||||
populate_list (void)
|
||||
{
|
||||
GtkWidget *list;
|
||||
|
||||
list = create_weather_view ();
|
||||
|
||||
hincrement = 5;
|
||||
vincrement = 0;
|
||||
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), list);
|
||||
}
|
||||
|
||||
extern GtkWidget *create_color_grid (void);
|
||||
|
||||
static void
|
||||
populate_grid (void)
|
||||
{
|
||||
GtkWidget *list;
|
||||
|
||||
list = create_color_grid ();
|
||||
|
||||
hincrement = 0;
|
||||
vincrement = 5;
|
||||
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow),
|
||||
GTK_POLICY_AUTOMATIC,
|
||||
GTK_POLICY_AUTOMATIC);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolledwindow), list);
|
||||
}
|
||||
|
||||
static void
|
||||
set_widget_type (int type)
|
||||
{
|
||||
@@ -164,6 +203,16 @@ set_widget_type (int type)
|
||||
populate_image ();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a list");
|
||||
populate_list ();
|
||||
break;
|
||||
|
||||
case 5:
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Scrolling a grid");
|
||||
populate_grid ();
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
/* Lists/Application launcher
|
||||
*
|
||||
* This demo uses the GtkCoverFlow widget as a fancy application launcher.
|
||||
*
|
||||
* It is also a very small introduction to listviews.
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/* This is the function that creates the #GListModel that we need.
|
||||
* GTK list widgets need a #GListModel to display, as models support change
|
||||
* notifications.
|
||||
* Unfortunately various older APIs do not provide list models, so we create
|
||||
* our own.
|
||||
*/
|
||||
static GListModel *
|
||||
create_application_list (void)
|
||||
{
|
||||
GListStore *store;
|
||||
GList *apps, *l;
|
||||
|
||||
/* We use a #GListStore here, which is a simple array-like list implementation
|
||||
* for manual management.
|
||||
* List models need to know what type of data they provide, so we need to
|
||||
* provide the type here. As we want to do a list of applications, #GAppInfo
|
||||
* is the object we provide.
|
||||
*/
|
||||
store = g_list_store_new (G_TYPE_APP_INFO);
|
||||
|
||||
apps = g_app_info_get_all ();
|
||||
|
||||
for (l = apps; l; l = l->next)
|
||||
{
|
||||
g_list_store_append (store, l->data);
|
||||
}
|
||||
|
||||
g_list_free_full (apps, g_object_unref);
|
||||
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
|
||||
/* This is the function we use for setting up new listitems to display.
|
||||
* We add just a #GtkImage here to display the application's icon as this is just
|
||||
* a simple demo.
|
||||
*/
|
||||
static void
|
||||
setup_listitem_cb (GtkListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *image;
|
||||
|
||||
image = gtk_image_new ();
|
||||
gtk_image_set_icon_size (GTK_IMAGE (image), GTK_ICON_SIZE_LARGE);
|
||||
|
||||
gtk_list_item_set_child (list_item, image);
|
||||
}
|
||||
|
||||
/* Here we need to prepare the listitem for displaying its item. We get the
|
||||
* listitem already set up from the previous function, so we can reuse the
|
||||
* #GtkImage widget we set up above.
|
||||
* We get the item - which we know is a #GAppInfo because it comes out of
|
||||
* the model we set up above, grab its icon and display it.
|
||||
*/
|
||||
static void
|
||||
bind_listitem_cb (GtkListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *image;
|
||||
GAppInfo *app_info;
|
||||
|
||||
image = gtk_list_item_get_child (list_item);
|
||||
app_info = gtk_list_item_get_item (list_item);
|
||||
|
||||
gtk_image_set_from_gicon (GTK_IMAGE (image), g_app_info_get_icon (app_info));
|
||||
}
|
||||
|
||||
/* In more complex code, we would also need functions to unbind and teardown
|
||||
* the listitem, but this is simple code, so the default implementations are
|
||||
* enough. If we had connected signals, this step would have been necessary.
|
||||
*
|
||||
* The #GtkSignalListItemFactory documentation contains more information about
|
||||
* this step.
|
||||
*/
|
||||
|
||||
/* This function is called whenever an item in the list is activated. This is
|
||||
* the simple way to allow reacting to the Enter key or double-clicking on a
|
||||
* listitem.
|
||||
* Of course, it is possible to use far more complex interactions by turning
|
||||
* off activation and adding buttons or other widgets in the setup function
|
||||
* above, but this is a simple demo, so we'll use the simple way.
|
||||
*/
|
||||
static void
|
||||
activate_cb (GtkCoverFlow *coverflow,
|
||||
guint position,
|
||||
gpointer unused)
|
||||
{
|
||||
GAppInfo *app_info;
|
||||
GdkAppLaunchContext *context;
|
||||
GError *error = NULL;
|
||||
|
||||
app_info = g_list_model_get_item (gtk_cover_flow_get_model (coverflow), position);
|
||||
|
||||
/* Prepare the context for launching the application and launch it. This
|
||||
* code is explained in detail in the documentation for #GdkAppLaunchContext
|
||||
* and #GAppInfo.
|
||||
*/
|
||||
context = gdk_display_get_app_launch_context (gtk_widget_get_display (GTK_WIDGET (coverflow)));
|
||||
if (!g_app_info_launch (app_info,
|
||||
NULL,
|
||||
G_APP_LAUNCH_CONTEXT (context),
|
||||
&error))
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
|
||||
/* And because error handling is important, even a simple demo has it:
|
||||
* We display an error dialog that something went wrong.
|
||||
*/
|
||||
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (coverflow))),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
||||
GTK_MESSAGE_ERROR,
|
||||
GTK_BUTTONS_CLOSE,
|
||||
"Could not launch %s", g_app_info_get_display_name (app_info));
|
||||
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
|
||||
g_clear_error (&error);
|
||||
gtk_widget_show (dialog);
|
||||
}
|
||||
|
||||
g_object_unref (context);
|
||||
g_object_unref (app_info);
|
||||
}
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
GtkWidget *
|
||||
do_listview_applauncher (GtkWidget *do_widget)
|
||||
{
|
||||
if (window == NULL)
|
||||
{
|
||||
GtkWidget *coverflow, *sw;;
|
||||
GListModel *model;
|
||||
GtkListItemFactory *factory;
|
||||
|
||||
/* Create a window and set a few defaults */
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 640, 320);
|
||||
gtk_window_set_display (GTK_WINDOW (window),
|
||||
gtk_widget_get_display (do_widget));
|
||||
gtk_window_set_title (GTK_WINDOW (window), "Application Launcher");
|
||||
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *) &window);
|
||||
|
||||
/* The #GtkListitemFactory is what is used to create #GtkListItems
|
||||
* to display the data from the model. So it is absolutely necessary
|
||||
* to create one.
|
||||
* We will use a #GtkSignalListItemFactory because it is the simplest
|
||||
* one to use. Different ones are available for different use cases.
|
||||
* The most powerful one is #GtkBuilderListItemFactory which uses
|
||||
* #GtkBuilder .ui files, so it requires little code.
|
||||
*/
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem_cb), NULL);
|
||||
g_signal_connect (factory, "bind", G_CALLBACK (bind_listitem_cb), NULL);
|
||||
|
||||
/* Create the list widget here: We use a coverflow widget because it's
|
||||
* the coolest one. We could just as well use other list widgets such
|
||||
* as a #GtkListView or a #GtkGridView and the code would look very
|
||||
* similar.
|
||||
*/
|
||||
coverflow = gtk_cover_flow_new_with_factory (factory);
|
||||
/* We connect the activate signal here. It's the function we defined
|
||||
* above for launching the selected application.
|
||||
*/
|
||||
g_signal_connect (coverflow, "activate", G_CALLBACK (activate_cb), NULL);
|
||||
|
||||
/* And of course we need to set the data model. Here we call the function
|
||||
* we wrote above that gives us the list of applications. Then we set
|
||||
* it on the coverflow list widget.
|
||||
* The coverflow will now take items from the model and use the factory
|
||||
* to create as many listitems as it needs to show itself to the user.
|
||||
*/
|
||||
model = create_application_list ();
|
||||
gtk_cover_flow_set_model (GTK_COVER_FLOW (coverflow), model);
|
||||
g_object_unref (model);
|
||||
|
||||
/* List widgets should always be contained in a #GtkScrolledWindow,
|
||||
* because otherwise they might get too large or they might not
|
||||
* be scrollable.
|
||||
*/
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), coverflow);
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
return window;
|
||||
}
|
||||
@@ -310,6 +310,7 @@ setup_simple_listitem_cb (GtkListItemFactory *factory,
|
||||
color_expression = gtk_property_expression_new (GTK_TYPE_LIST_ITEM, expression, "item");
|
||||
|
||||
picture = gtk_picture_new ();
|
||||
gtk_widget_set_size_request (picture, 32, 32);
|
||||
gtk_expression_bind (color_expression, picture, "paintable", NULL);
|
||||
|
||||
gtk_list_item_set_child (list_item, picture);
|
||||
@@ -404,6 +405,34 @@ set_item (GBinding *binding,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
create_color_grid (void)
|
||||
{
|
||||
GtkWidget *gridview;
|
||||
GtkListItemFactory *factory;
|
||||
GListModel *model, *selection;
|
||||
|
||||
gridview = gtk_grid_view_new ();
|
||||
gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
|
||||
gtk_scrollable_set_vscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
|
||||
|
||||
factory = gtk_signal_list_item_factory_new ();
|
||||
g_signal_connect (factory, "setup", G_CALLBACK (setup_simple_listitem_cb), NULL);
|
||||
gtk_grid_view_set_factory (GTK_GRID_VIEW (gridview), factory);
|
||||
g_object_unref (factory);
|
||||
|
||||
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (gridview), 24);
|
||||
gtk_grid_view_set_enable_rubberband (GTK_GRID_VIEW (gridview), TRUE);
|
||||
|
||||
model = G_LIST_MODEL (gtk_sort_list_model_new (create_colors_model (), NULL));
|
||||
selection = G_LIST_MODEL (gtk_multi_selection_new (model));
|
||||
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), selection);
|
||||
g_object_unref (selection);
|
||||
g_object_unref (model);
|
||||
|
||||
return gridview;
|
||||
}
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
GtkWidget *
|
||||
@@ -415,7 +444,7 @@ do_listview_colors (GtkWidget *do_widget)
|
||||
GtkListItemFactory *factory;
|
||||
GListStore *factories;
|
||||
GListModel *model;
|
||||
GtkNoSelection *selection;
|
||||
|
||||
GtkSorter *sorter;
|
||||
GtkSorter *multi_sorter;
|
||||
GListStore *sorters;
|
||||
@@ -435,17 +464,10 @@ do_listview_colors (GtkWidget *do_widget)
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
||||
|
||||
gridview = gtk_grid_view_new ();
|
||||
gtk_scrollable_set_hscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
|
||||
gtk_scrollable_set_vscroll_policy (GTK_SCROLLABLE (gridview), GTK_SCROLL_NATURAL);
|
||||
|
||||
gtk_grid_view_set_max_columns (GTK_GRID_VIEW (gridview), 24);
|
||||
|
||||
model = G_LIST_MODEL (gtk_sort_list_model_new (create_colors_model (), NULL));
|
||||
selection = gtk_no_selection_new (model);
|
||||
gtk_grid_view_set_model (GTK_GRID_VIEW (gridview), G_LIST_MODEL (selection));
|
||||
gridview = create_color_grid ();
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), gridview);
|
||||
g_object_unref (selection);
|
||||
model = gtk_grid_view_get_model (GTK_GRID_VIEW (gridview));
|
||||
g_object_get (model, "model", &model, NULL);
|
||||
|
||||
sorters = g_list_store_new (GTK_TYPE_SORTER);
|
||||
|
||||
@@ -559,7 +581,6 @@ do_listview_colors (GtkWidget *do_widget)
|
||||
G_BINDING_SYNC_CREATE,
|
||||
set_item, NULL,
|
||||
NULL, NULL);
|
||||
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ enum {
|
||||
PROP_SUMMARY,
|
||||
PROP_DESCRIPTION,
|
||||
PROP_VALUE,
|
||||
PROP_TYPE,
|
||||
PROP_DEFAULT_VALUE,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
@@ -65,6 +67,21 @@ settings_key_get_property (GObject *object,
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_TYPE:
|
||||
{
|
||||
const GVariantType *type = g_settings_schema_key_get_value_type (self->key);
|
||||
g_value_set_string (value, g_variant_type_peek_string (type));
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_DEFAULT_VALUE:
|
||||
{
|
||||
GVariant *variant = g_settings_schema_key_get_default_value (self->key);
|
||||
g_value_take_string (value, g_variant_print (variant, FALSE));
|
||||
g_variant_unref (variant);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -98,6 +115,10 @@ settings_key_class_init (SettingsKeyClass *klass)
|
||||
g_param_spec_string ("summary", NULL, NULL, NULL, G_PARAM_READABLE);
|
||||
properties[PROP_VALUE] =
|
||||
g_param_spec_string ("value", NULL, NULL, NULL, G_PARAM_READABLE);
|
||||
properties[PROP_TYPE] =
|
||||
g_param_spec_string ("type", NULL, NULL, NULL, G_PARAM_READABLE);
|
||||
properties[PROP_DEFAULT_VALUE] =
|
||||
g_param_spec_string ("default-value", NULL, NULL, NULL, G_PARAM_READABLE);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
@@ -120,6 +120,58 @@
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title">Type</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<lookup name="type" type="SettingsKey">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title">Default</property>
|
||||
<property name="factory">
|
||||
<object class="GtkBuilderListItemFactory">
|
||||
<property name="bytes"><![CDATA[
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="GtkListItem">
|
||||
<property name="child">
|
||||
<object class="GtkLabel">
|
||||
<property name="xalign">0</property>
|
||||
<binding name="label">
|
||||
<lookup name="default-value" type="SettingsKey">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
|
||||
@@ -275,13 +275,33 @@ bind_widget (GtkListItem *list_item,
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
|
||||
GtkWidget *
|
||||
create_weather_view (void)
|
||||
{
|
||||
GtkWidget *listview;
|
||||
GListModel *model, *selection;
|
||||
|
||||
listview = gtk_list_view_new_with_factory (
|
||||
gtk_functions_list_item_factory_new (setup_widget,
|
||||
bind_widget,
|
||||
NULL, NULL));
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (listview), GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_list_view_set_show_separators (GTK_LIST_VIEW (listview), TRUE);
|
||||
model = create_weather_model ();
|
||||
selection = G_LIST_MODEL (gtk_no_selection_new (model));
|
||||
gtk_list_view_set_model (GTK_LIST_VIEW (listview), selection);
|
||||
g_object_unref (selection);
|
||||
g_object_unref (model);
|
||||
|
||||
return listview;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
do_listview_weather (GtkWidget *do_widget)
|
||||
{
|
||||
if (window == NULL)
|
||||
{
|
||||
GtkWidget *listview, *sw;;
|
||||
GListModel *model, *selection;
|
||||
|
||||
window = gtk_window_new ();
|
||||
gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
|
||||
@@ -293,19 +313,7 @@ do_listview_weather (GtkWidget *do_widget)
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_window_set_child (GTK_WINDOW (window), sw);
|
||||
|
||||
listview = gtk_list_view_new_with_factory (
|
||||
gtk_functions_list_item_factory_new (setup_widget,
|
||||
bind_widget,
|
||||
NULL, NULL));
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (listview), GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_list_view_set_show_separators (GTK_LIST_VIEW (listview), TRUE);
|
||||
model = create_weather_model ();
|
||||
selection = G_LIST_MODEL (gtk_no_selection_new (model));
|
||||
gtk_list_view_set_model (GTK_LIST_VIEW (listview), selection);
|
||||
g_object_unref (selection);
|
||||
g_object_unref (model);
|
||||
|
||||
listview = create_weather_view ();
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), listview);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,6 @@ demos = files([
|
||||
'listbox.c',
|
||||
'flowbox.c',
|
||||
'list_store.c',
|
||||
'listview_applauncher.c',
|
||||
'listview_clocks.c',
|
||||
'listview_colors.c',
|
||||
'listview_filebrowser.c',
|
||||
|
||||
@@ -251,6 +251,8 @@ puzzle_button_pressed (GtkGestureClick *gesture,
|
||||
{
|
||||
gtk_widget_error_bell (grid);
|
||||
}
|
||||
|
||||
check_solved (grid);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -291,6 +293,8 @@ start_puzzle (GdkPaintable *paintable)
|
||||
/* Add shortcuts so people can use the arrow
|
||||
* keys to move the puzzle */
|
||||
controller = gtk_shortcut_controller_new ();
|
||||
gtk_shortcut_controller_set_scope (GTK_SHORTCUT_CONTROLLER (controller),
|
||||
GTK_SHORTCUT_SCOPE_GLOBAL);
|
||||
add_move_binding (GTK_SHORTCUT_CONTROLLER (controller),
|
||||
GDK_KEY_Left, GDK_KEY_KP_Left,
|
||||
-1, 0);
|
||||
@@ -351,11 +355,16 @@ reshuffle (void)
|
||||
{
|
||||
GtkWidget *grid;
|
||||
|
||||
grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
|
||||
if (solved)
|
||||
start_puzzle (puzzle);
|
||||
{
|
||||
start_puzzle (puzzle);
|
||||
grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
|
||||
}
|
||||
else
|
||||
shuffle_puzzle (grid);
|
||||
{
|
||||
grid = gtk_aspect_frame_get_child (GTK_ASPECT_FRAME (frame));
|
||||
shuffle_puzzle (grid);
|
||||
}
|
||||
gtk_widget_grab_focus (grid);
|
||||
}
|
||||
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
<xi:include href="xml/gtkselectionmodel.xml" />
|
||||
<xi:include href="xml/gtknoselection.xml" />
|
||||
<xi:include href="xml/gtksingleselection.xml" />
|
||||
<xi:include href="xml/gtkmultiselection.xml" />
|
||||
<xi:include href="xml/gtkdirectorylist.xml" />
|
||||
</chapter>
|
||||
|
||||
|
||||
@@ -392,6 +392,16 @@ gtk_single_selection_set_can_unselect
|
||||
gtk_single_selection_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtkmultiselection</FILE>
|
||||
<TITLE>GtkMultiSeledction</TITLE>
|
||||
GtkMultiSelection
|
||||
gtk_multi_selection_new
|
||||
gtk_multi_selection_copy
|
||||
<SUBSECTION Private>
|
||||
gtk_multi_selection_get_type
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gtklistitem</FILE>
|
||||
<TITLE>GtkListItem</TITLE>
|
||||
@@ -479,6 +489,11 @@ gtk_list_view_set_show_separators
|
||||
gtk_list_view_get_show_separators
|
||||
gtk_list_view_set_single_click_activate
|
||||
gtk_list_view_get_single_click_activate
|
||||
gtk_list_view_set_enable_rubberband
|
||||
gtk_list_view_get_enable_rubberband
|
||||
gtk_list_view_set_search_filter
|
||||
gtk_list_view_get_search_filter
|
||||
gtk_list_view_next_match
|
||||
<SUBSECTION Standard>
|
||||
GTK_LIST_VIEW
|
||||
GTK_LIST_VIEW_CLASS
|
||||
@@ -496,6 +511,7 @@ gtk_list_view_get_type
|
||||
GtkColumnView
|
||||
gtk_column_view_new
|
||||
gtk_column_view_append_column
|
||||
gtk_column_view_insert_column
|
||||
gtk_column_view_remove_column
|
||||
gtk_column_view_get_columns
|
||||
gtk_column_view_get_model
|
||||
@@ -506,6 +522,11 @@ gtk_column_view_set_show_separators
|
||||
gtk_column_view_sort_by_column
|
||||
gtk_column_view_set_single_click_activate
|
||||
gtk_column_view_get_single_click_activate
|
||||
gtk_column_view_set_enable_rubberband
|
||||
gtk_column_view_get_enable_rubberband
|
||||
gtk_column_view_set_search_filter
|
||||
gtk_column_view_get_search_filter
|
||||
gtk_column_view_next_match
|
||||
<SUBSECTION Standard>
|
||||
GTK_COLUMN_VIEW
|
||||
GTK_COLUMN_VIEW_CLASS
|
||||
@@ -530,6 +551,14 @@ gtk_column_view_column_set_title
|
||||
gtk_column_view_column_get_title
|
||||
gtk_column_view_column_set_sorter
|
||||
gtk_column_view_column_get_sorter
|
||||
gtk_column_view_column_set_visible
|
||||
gtk_column_view_column_get_visible
|
||||
gtk_column_view_column_set_reorderable
|
||||
gtk_column_view_column_get_reorderable
|
||||
gtk_column_view_column_set_fixed_width
|
||||
gtk_column_view_column_get_fixed_width
|
||||
gtk_column_view_column_set_expand
|
||||
gtk_column_view_column_get_expand
|
||||
<SUBSECTION Standard>
|
||||
GTK_COLUMN_VIEW_COLUMN
|
||||
GTK_COLUMN_VIEW_COLUMN_CLASS
|
||||
@@ -554,6 +583,11 @@ gtk_grid_view_set_min_columns
|
||||
gtk_grid_view_get_min_columns
|
||||
gtk_grid_view_set_single_click_activate
|
||||
gtk_grid_view_get_single_click_activate
|
||||
gtk_grid_view_set_enable_rubberband
|
||||
gtk_grid_view_get_enable_rubberband
|
||||
gtk_grid_view_set_search_filter
|
||||
gtk_grid_view_get_search_filter
|
||||
gtk_grid_view_next_match
|
||||
<SUBSECTION Standard>
|
||||
GTK_GRID_VIEW
|
||||
GTK_GRID_VIEW_CLASS
|
||||
|
||||
@@ -139,6 +139,7 @@ gtk_menu_button_get_type
|
||||
gtk_message_dialog_get_type
|
||||
gtk_mount_operation_get_type
|
||||
gtk_multi_filter_get_type
|
||||
gtk_multi_selection_get_type
|
||||
gtk_multi_sorter_get_type
|
||||
gtk_native_get_type
|
||||
gtk_native_dialog_get_type
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2011 Chun-wei Fan <fanc999@yahoo.com.tw>
|
||||
*
|
||||
* Author: Chun-wei Fan <fanc999@yahoo.com.tw>
|
||||
*
|
||||
* 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 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/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#ifndef HAVE_DECL_ISNAN
|
||||
/* it seems of the supported compilers only
|
||||
* MSVC does not have isnan(), but it does
|
||||
* have _isnan() which does the same as isnan()
|
||||
*/
|
||||
static inline gboolean
|
||||
isnan (double x)
|
||||
{
|
||||
return _isnan (x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DECL_ISINF
|
||||
/* Unfortunately MSVC does not have finite()
|
||||
* but it does have _finite() which is the same
|
||||
* as finite() except when x is a NaN
|
||||
*/
|
||||
static inline gboolean
|
||||
isinf (double x)
|
||||
{
|
||||
return (!_finite (x) && !_isnan (x));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Workaround for round() for non-GCC/non-C99 compilers */
|
||||
#ifndef HAVE_ROUND
|
||||
static inline double
|
||||
round (double x)
|
||||
{
|
||||
if (x >= 0)
|
||||
return floor (x + 0.5);
|
||||
else
|
||||
return ceil (x - 0.5);
|
||||
}
|
||||
#endif
|
||||
@@ -26,9 +26,6 @@
|
||||
#include "gdkintl.h"
|
||||
#include "gdkkeysprivate.h"
|
||||
|
||||
/* for the use of round() */
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/**
|
||||
* SECTION:gdkdevice
|
||||
* @Short_description: Object representing an input device
|
||||
|
||||
+4
-7
@@ -38,9 +38,6 @@
|
||||
#include <math.h>
|
||||
#include <glib.h>
|
||||
|
||||
/* for the use of round() */
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/**
|
||||
* SECTION:gdkdisplay
|
||||
* @Short_description: Controls a set of monitors and their associated input devices
|
||||
@@ -1735,11 +1732,11 @@ gdk_display_map_keycode (GdkDisplay *display,
|
||||
* @keycode: a keycode
|
||||
* @state: a modifier state
|
||||
* @group: active keyboard group
|
||||
* @keyval: (out) (allow-none): return location for keyval, or %NULL
|
||||
* @effective_group: (out) (allow-none): return location for effective
|
||||
* @keyval: (out) (optional): return location for keyval, or %NULL
|
||||
* @effective_group: (out) (optional): return location for effective
|
||||
* group, or %NULL
|
||||
* @level: (out) (allow-none): return location for level, or %NULL
|
||||
* @consumed_modifiers: (out) (allow-none): return location for modifiers
|
||||
* @level: (out) (optional): return location for level, or %NULL
|
||||
* @consumed: (out) (optional): return location for modifiers
|
||||
* that were used to determine the group or level, or %NULL
|
||||
*
|
||||
* Translates the contents of a #GdkEventKey (ie @keycode, @state, and @group)
|
||||
|
||||
+3
-25
@@ -2130,7 +2130,7 @@ gdk_focus_event_new (GdkSurface *surface,
|
||||
|
||||
/**
|
||||
* gdk_focus_event_get_in:
|
||||
* @event: (type GdkScrollEvent): a focus change event
|
||||
* @event: (type GdkFocusEvent): a focus change event
|
||||
*
|
||||
* Extracts whether this event is about focus entering or
|
||||
* leaving the surface.
|
||||
@@ -2152,15 +2152,6 @@ gdk_focus_event_get_in (GdkEvent *event)
|
||||
|
||||
/* {{{ GdkScrollEvent */
|
||||
|
||||
static void
|
||||
gdk_scroll_event_init (GdkEvent *event)
|
||||
{
|
||||
GdkScrollEvent *self = (GdkScrollEvent *) event;
|
||||
|
||||
self->x = NAN;
|
||||
self->y = NAN;
|
||||
}
|
||||
|
||||
static void
|
||||
gdk_scroll_event_finalize (GdkEvent *event)
|
||||
{
|
||||
@@ -2179,19 +2170,6 @@ gdk_scroll_event_get_state (GdkEvent *event)
|
||||
return self->state;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gdk_scroll_event_get_position (GdkEvent *event,
|
||||
double *x,
|
||||
double *y)
|
||||
{
|
||||
GdkScrollEvent *self = (GdkScrollEvent *) event;
|
||||
|
||||
*x = self->x;
|
||||
*y = self->y;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GdkDeviceTool *
|
||||
gdk_scroll_event_get_tool (GdkEvent *event)
|
||||
{
|
||||
@@ -2202,10 +2180,10 @@ gdk_scroll_event_get_tool (GdkEvent *event)
|
||||
|
||||
static const GdkEventTypeInfo gdk_scroll_event_info = {
|
||||
sizeof (GdkScrollEvent),
|
||||
gdk_scroll_event_init,
|
||||
NULL,
|
||||
gdk_scroll_event_finalize,
|
||||
gdk_scroll_event_get_state,
|
||||
gdk_scroll_event_get_position,
|
||||
NULL,
|
||||
NULL,
|
||||
gdk_scroll_event_get_tool,
|
||||
NULL,
|
||||
|
||||
@@ -225,8 +225,6 @@ struct _GdkScrollEvent
|
||||
{
|
||||
GdkEvent parent_instance;
|
||||
|
||||
double x;
|
||||
double y;
|
||||
GdkModifierType state;
|
||||
GdkScrollDirection direction;
|
||||
double delta_x;
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
#include <errno.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/**
|
||||
* SECTION:rgba_colors
|
||||
* @Short_description: RGBA colors
|
||||
|
||||
@@ -47,9 +47,6 @@
|
||||
|
||||
#include <epoxy/gl.h>
|
||||
|
||||
/* for the use of round() */
|
||||
#include "fallback-c89.c"
|
||||
|
||||
#ifdef GDK_WINDOWING_WAYLAND
|
||||
#include "wayland/gdkwayland.h"
|
||||
#endif
|
||||
|
||||
@@ -49,7 +49,6 @@
|
||||
#include <cairo-win32.h>
|
||||
#include <dwmapi.h>
|
||||
#include <math.h>
|
||||
#include "fallback-c89.c"
|
||||
|
||||
static void gdk_surface_win32_finalize (GObject *object);
|
||||
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* Copyright (C) 2011 Chun-wei Fan <fanc999@yahoo.com.tw>
|
||||
*
|
||||
* Author: Chun-wei Fan <fanc999@yahoo.com.tw>
|
||||
*
|
||||
* 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 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/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/* Workaround for round() for non-GCC/non-C99 compilers */
|
||||
#ifndef HAVE_ROUND
|
||||
static inline double
|
||||
round (double x)
|
||||
{
|
||||
if (x >= 0)
|
||||
return floor (x + 0.5);
|
||||
else
|
||||
return ceil (x - 0.5);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Workaround for rint() for non-GCC/non-C99 compilers */
|
||||
#ifndef HAVE_RINT
|
||||
static inline double
|
||||
rint (double x)
|
||||
{
|
||||
if (ceil (x + 0.5) == floor (x + 0.5))
|
||||
{
|
||||
int a;
|
||||
a = (int) ceil (x);
|
||||
if (a % 2 == 0)
|
||||
return ceil (x);
|
||||
else
|
||||
return floor (x);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x >= 0)
|
||||
return floor (x + 0.5);
|
||||
else
|
||||
return ceil (x - 0.5);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_NEARBYINT
|
||||
/* Workaround for nearbyint() for non-GCC/non-C99 compilers */
|
||||
/* This is quite similar to rint() in most respects */
|
||||
|
||||
static inline double
|
||||
nearbyint (double x)
|
||||
{
|
||||
return floor (x + 0.5);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DECL_ISINF
|
||||
/* Unfortunately MSVC does not have finite()
|
||||
* but it does have _finite() which is the same
|
||||
* as finite() except when x is a NaN
|
||||
*/
|
||||
static inline gboolean
|
||||
isinf (double x)
|
||||
{
|
||||
return (!_finite (x) && !_isnan (x));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DECL_ISNAN
|
||||
/* it seems of the supported compilers only
|
||||
* MSVC does not have isnan(), but it does
|
||||
* have _isnan() which does the same as isnan()
|
||||
*/
|
||||
static inline gboolean
|
||||
isnan (double x)
|
||||
{
|
||||
return _isnan (x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_DECL_ISNANF
|
||||
#if 1
|
||||
#define isnanf(x) isnan(x)
|
||||
#else
|
||||
/* it seems of the supported compilers only
|
||||
* MSVC does not have isnanf(), but it does
|
||||
* have _isnanf() which does the same as isnanf()
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
static inline gboolean
|
||||
isnanf (float x)
|
||||
{
|
||||
return _isnanf (x);
|
||||
}
|
||||
#elif defined (__GNUC__)
|
||||
/* gcc has an intern function that it warns about when
|
||||
* using -Wshadow but no header properly declares it,
|
||||
* so we do it instead.
|
||||
*/
|
||||
extern int isnanf (float x);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef INFINITY
|
||||
/* define INFINITY for compilers that lack support for it */
|
||||
# ifdef HUGE_VALF
|
||||
# define INFINITY HUGE_VALF
|
||||
# else
|
||||
# define INFINITY (float)HUGE_VAL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_LOG2
|
||||
/* Use a simple implementation for log2() for compilers that lack it */
|
||||
static inline double
|
||||
log2 (double x)
|
||||
{
|
||||
return log (x) / log (2.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_EXP2
|
||||
/* Use a simple implementation for exp2() for compilers that lack it */
|
||||
static inline double
|
||||
exp2 (double x)
|
||||
{
|
||||
return pow (2.0, x);
|
||||
}
|
||||
#endif
|
||||
@@ -85,7 +85,6 @@
|
||||
#include <gtk/gtkcomboboxtext.h>
|
||||
#include <gtk/gtkconstraintlayout.h>
|
||||
#include <gtk/gtkconstraint.h>
|
||||
#include <gtk/gtkcoverflow.h>
|
||||
#include <gtk/gtkcssprovider.h>
|
||||
#include <gtk/gtkcustomlayout.h>
|
||||
#include <gtk/gtkcustomsorter.h>
|
||||
@@ -175,6 +174,7 @@
|
||||
#include <gtk/gtkmessagedialog.h>
|
||||
#include <gtk/gtkmountoperation.h>
|
||||
#include <gtk/gtkmultifilter.h>
|
||||
#include <gtk/gtkmultiselection.h>
|
||||
#include <gtk/gtkmultisorter.h>
|
||||
#include <gtk/gtknative.h>
|
||||
#include <gtk/gtknativedialog.h>
|
||||
|
||||
+691
-36
@@ -34,6 +34,13 @@
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkscrollable.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtksizerequest.h"
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkeventcontrollermotion.h"
|
||||
#include "gtkdragsource.h"
|
||||
#include "gtkeventcontrollerkey.h"
|
||||
#include "gtklistbaseprivate.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkcolumnview
|
||||
@@ -63,6 +70,21 @@ struct _GtkColumnView
|
||||
GtkColumnListItemFactory *factory;
|
||||
|
||||
GtkSorter *sorter;
|
||||
|
||||
GtkAdjustment *hadjustment;
|
||||
|
||||
gboolean in_column_resize;
|
||||
gboolean in_column_reorder;
|
||||
int drag_pos;
|
||||
int drag_x;
|
||||
int drag_offset;
|
||||
int drag_column_x;
|
||||
|
||||
GtkGesture *drag_gesture;
|
||||
|
||||
guint autoscroll_id;
|
||||
double autoscroll_x;
|
||||
double autoscroll_delta;
|
||||
};
|
||||
|
||||
struct _GtkColumnViewClass
|
||||
@@ -82,6 +104,8 @@ enum
|
||||
PROP_VADJUSTMENT,
|
||||
PROP_VSCROLL_POLICY,
|
||||
PROP_SINGLE_CLICK_ACTIVATE,
|
||||
PROP_ENABLE_RUBBERBAND,
|
||||
PROP_SEARCH_FILTER,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
@@ -169,48 +193,77 @@ gtk_column_view_allocate_columns (GtkColumnView *self,
|
||||
int width)
|
||||
{
|
||||
GtkScrollablePolicy scroll_policy;
|
||||
int col_min, col_nat, widget_min, widget_nat, extra, col_size, x;
|
||||
int col_min, col_nat, extra, col_size, x;
|
||||
int n, n_expand, expand_size, n_extra;
|
||||
guint i;
|
||||
GtkRequestedSize *sizes;
|
||||
|
||||
gtk_column_view_measure_across (self, &col_min, &col_nat);
|
||||
gtk_widget_measure (GTK_WIDGET (self),
|
||||
GTK_ORIENTATION_HORIZONTAL, -1,
|
||||
&widget_min, &widget_nat,
|
||||
NULL, NULL);
|
||||
|
||||
scroll_policy = gtk_scrollable_get_hscroll_policy (GTK_SCROLLABLE (self->listview));
|
||||
if (scroll_policy == GTK_SCROLL_MINIMUM)
|
||||
{
|
||||
extra = widget_min - col_min;
|
||||
col_size = col_min;
|
||||
}
|
||||
else
|
||||
{
|
||||
extra = widget_nat - col_nat;
|
||||
col_size = col_nat;
|
||||
}
|
||||
width -= extra;
|
||||
width = MAX (width, col_size);
|
||||
|
||||
x = 0;
|
||||
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)); i++)
|
||||
n = g_list_model_get_n_items (G_LIST_MODEL (self->columns));
|
||||
n_expand = 0;
|
||||
sizes = g_newa (GtkRequestedSize, n);
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GtkColumnViewColumn *column;
|
||||
|
||||
column = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
|
||||
gtk_column_view_column_measure (column, &col_min, &col_nat);
|
||||
if (scroll_policy == GTK_SCROLL_MINIMUM)
|
||||
col_size = col_min;
|
||||
if (gtk_column_view_column_get_visible (column))
|
||||
{
|
||||
gtk_column_view_column_measure (column, &sizes[i].minimum_size, &sizes[i].natural_size);
|
||||
if (gtk_column_view_column_get_expand (column))
|
||||
n_expand++;
|
||||
}
|
||||
else
|
||||
col_size = col_nat;
|
||||
sizes[i].minimum_size = sizes[i].natural_size = 0;
|
||||
g_object_unref (column);
|
||||
}
|
||||
|
||||
gtk_column_view_column_allocate (column, x, col_size);
|
||||
x += col_size;
|
||||
gtk_column_view_measure_across (self, &col_min, &col_nat);
|
||||
|
||||
scroll_policy = gtk_scrollable_get_hscroll_policy (GTK_SCROLLABLE (self->listview));
|
||||
if (scroll_policy == GTK_SCROLL_MINIMUM)
|
||||
extra = MAX (width - col_min, 0);
|
||||
else
|
||||
extra = MAX (width - col_min, col_nat - col_min);
|
||||
|
||||
extra = gtk_distribute_natural_allocation (extra, n, sizes);
|
||||
if (n_expand > 0)
|
||||
{
|
||||
expand_size = extra / n_expand;
|
||||
n_extra = extra % n_expand;
|
||||
}
|
||||
else
|
||||
expand_size = n_extra = 0;
|
||||
|
||||
x = 0;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GtkColumnViewColumn *column;
|
||||
|
||||
column = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
|
||||
if (gtk_column_view_column_get_visible (column))
|
||||
{
|
||||
col_size = sizes[i].minimum_size;
|
||||
if (gtk_column_view_column_get_expand (column))
|
||||
{
|
||||
col_size += expand_size;
|
||||
if (n_extra > 0)
|
||||
{
|
||||
col_size++;
|
||||
n_extra--;
|
||||
}
|
||||
}
|
||||
|
||||
gtk_column_view_column_allocate (column, x, col_size);
|
||||
if (self->in_column_reorder && i == self->drag_pos)
|
||||
gtk_column_view_column_set_header_position (column, self->drag_x);
|
||||
|
||||
x += col_size;
|
||||
}
|
||||
|
||||
g_object_unref (column);
|
||||
}
|
||||
|
||||
return width + extra;
|
||||
return x;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -220,8 +273,9 @@ gtk_column_view_allocate (GtkWidget *widget,
|
||||
int baseline)
|
||||
{
|
||||
GtkColumnView *self = GTK_COLUMN_VIEW (widget);
|
||||
int full_width, header_height, min, nat;
|
||||
int full_width, header_height, min, nat, x;
|
||||
|
||||
x = gtk_adjustment_get_value (self->hadjustment);
|
||||
full_width = gtk_column_view_allocate_columns (self, width);
|
||||
|
||||
gtk_widget_measure (self->header, GTK_ORIENTATION_VERTICAL, full_width, &min, &nat, NULL, NULL);
|
||||
@@ -229,11 +283,14 @@ gtk_column_view_allocate (GtkWidget *widget,
|
||||
header_height = min;
|
||||
else
|
||||
header_height = nat;
|
||||
gtk_widget_allocate (self->header, full_width, header_height, -1, NULL);
|
||||
gtk_widget_allocate (self->header, full_width, header_height, -1,
|
||||
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (-x, 0)));
|
||||
|
||||
gtk_widget_allocate (GTK_WIDGET (self->listview),
|
||||
full_width, height - header_height, -1,
|
||||
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (0, header_height)));
|
||||
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (-x, header_height)));
|
||||
|
||||
gtk_adjustment_configure (self->hadjustment, x, 0, full_width, width * 0.1, width * 0.9, width);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -244,6 +301,23 @@ gtk_column_view_activate_cb (GtkListView *listview,
|
||||
g_signal_emit (self, signals[ACTIVATE], 0, pos);
|
||||
}
|
||||
|
||||
static void
|
||||
adjustment_value_changed_cb (GtkAdjustment *adjustment,
|
||||
GtkColumnView *self)
|
||||
{
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
clear_adjustment (GtkColumnView *self)
|
||||
{
|
||||
if (self->hadjustment == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->hadjustment, adjustment_value_changed_cb, self);
|
||||
g_clear_object (&self->hadjustment);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_column_view_dispose (GObject *object)
|
||||
{
|
||||
@@ -262,6 +336,7 @@ gtk_column_view_dispose (GObject *object)
|
||||
g_clear_object (&self->factory);
|
||||
|
||||
g_clear_object (&self->sorter);
|
||||
clear_adjustment (self);
|
||||
|
||||
G_OBJECT_CLASS (gtk_column_view_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -291,7 +366,7 @@ gtk_column_view_get_property (GObject *object,
|
||||
break;
|
||||
|
||||
case PROP_HADJUSTMENT:
|
||||
g_value_set_object (value, gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (self->listview)));
|
||||
g_value_set_object (value, self->hadjustment);
|
||||
break;
|
||||
|
||||
case PROP_HSCROLL_POLICY:
|
||||
@@ -322,6 +397,14 @@ gtk_column_view_get_property (GObject *object,
|
||||
g_value_set_boolean (value, gtk_column_view_get_single_click_activate (self));
|
||||
break;
|
||||
|
||||
case PROP_ENABLE_RUBBERBAND:
|
||||
g_value_set_boolean (value, gtk_column_view_get_enable_rubberband (self));
|
||||
break;
|
||||
|
||||
case PROP_SEARCH_FILTER:
|
||||
g_value_set_object (value, gtk_column_view_get_search_filter (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -335,13 +418,24 @@ gtk_column_view_set_property (GObject *object,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkColumnView *self = GTK_COLUMN_VIEW (object);
|
||||
GtkAdjustment *adjustment;
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_HADJUSTMENT:
|
||||
if (gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (self->listview)) != g_value_get_object (value))
|
||||
adjustment = g_value_get_object (value);
|
||||
if (adjustment == NULL)
|
||||
adjustment = gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
|
||||
g_object_ref_sink (adjustment);
|
||||
|
||||
if (self->hadjustment != adjustment)
|
||||
{
|
||||
gtk_scrollable_set_hadjustment (GTK_SCROLLABLE (self->listview), g_value_get_object (value));
|
||||
clear_adjustment (self);
|
||||
|
||||
self->hadjustment = adjustment;
|
||||
|
||||
g_signal_connect (adjustment, "value-changed", G_CALLBACK (adjustment_value_changed_cb), self);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HADJUSTMENT]);
|
||||
}
|
||||
break;
|
||||
@@ -382,6 +476,14 @@ gtk_column_view_set_property (GObject *object,
|
||||
gtk_column_view_set_single_click_activate (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_ENABLE_RUBBERBAND:
|
||||
gtk_column_view_set_enable_rubberband (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_SEARCH_FILTER:
|
||||
gtk_column_view_set_search_filter (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -478,6 +580,30 @@ gtk_column_view_class_init (GtkColumnViewClass *klass)
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkColumnView:enable-rubberband:
|
||||
*
|
||||
* Allow rubberband selection
|
||||
*/
|
||||
properties[PROP_ENABLE_RUBBERBAND] =
|
||||
g_param_spec_boolean ("enable-rubberband",
|
||||
P_("Enable rubberband selection"),
|
||||
P_("Allow selecting items by dragging with the mouse"),
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkColumnView:search-filter:
|
||||
*
|
||||
* Filter used for search
|
||||
*/
|
||||
properties[PROP_SEARCH_FILTER] =
|
||||
g_param_spec_object ("search-filter",
|
||||
P_("Search filter"),
|
||||
P_("Filter used for searching"),
|
||||
GTK_TYPE_FILTER,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
|
||||
/**
|
||||
@@ -507,9 +633,366 @@ gtk_column_view_class_init (GtkColumnViewClass *klass)
|
||||
gtk_widget_class_set_css_name (widget_class, I_("treeview"));
|
||||
}
|
||||
|
||||
static void update_column_resize (GtkColumnView *self,
|
||||
double x);
|
||||
static void update_column_reorder (GtkColumnView *self,
|
||||
double x);
|
||||
|
||||
static gboolean
|
||||
autoscroll_cb (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
gpointer data)
|
||||
{
|
||||
GtkColumnView *self = data;
|
||||
|
||||
gtk_adjustment_set_value (self->hadjustment,
|
||||
gtk_adjustment_get_value (self->hadjustment) + self->autoscroll_delta);
|
||||
|
||||
self->autoscroll_x += self->autoscroll_delta;
|
||||
|
||||
if (self->in_column_resize)
|
||||
update_column_resize (self, self->autoscroll_x);
|
||||
else if (self->in_column_reorder)
|
||||
update_column_reorder (self, self->autoscroll_x);
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
add_autoscroll (GtkColumnView *self,
|
||||
double x,
|
||||
double delta)
|
||||
{
|
||||
self->autoscroll_x = x;
|
||||
self->autoscroll_delta = delta;
|
||||
|
||||
if (self->autoscroll_id == 0)
|
||||
self->autoscroll_id = gtk_widget_add_tick_callback (GTK_WIDGET (self), autoscroll_cb, self, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_autoscroll (GtkColumnView *self)
|
||||
{
|
||||
if (self->autoscroll_id != 0)
|
||||
{
|
||||
gtk_widget_remove_tick_callback (GTK_WIDGET (self), self->autoscroll_id);
|
||||
self->autoscroll_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define DRAG_WIDTH 6
|
||||
|
||||
static gboolean
|
||||
gtk_column_view_in_resize_rect (GtkColumnView *self,
|
||||
GtkColumnViewColumn *column,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
GtkWidget *header;
|
||||
graphene_rect_t rect;
|
||||
|
||||
header = gtk_column_view_column_get_header (column);
|
||||
|
||||
if (!gtk_widget_compute_bounds (header, self->header, &rect))
|
||||
return FALSE;
|
||||
|
||||
rect.origin.x += rect.size.width - DRAG_WIDTH / 2;
|
||||
rect.size.width = DRAG_WIDTH;
|
||||
|
||||
return graphene_rect_contains_point (&rect, &(graphene_point_t) { x, y});
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_column_view_in_header (GtkColumnView *self,
|
||||
GtkColumnViewColumn *column,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
GtkWidget *header;
|
||||
graphene_rect_t rect;
|
||||
|
||||
header = gtk_column_view_column_get_header (column);
|
||||
|
||||
if (!gtk_widget_compute_bounds (header, self->header, &rect))
|
||||
return FALSE;
|
||||
|
||||
return graphene_rect_contains_point (&rect, &(graphene_point_t) { x, y});
|
||||
}
|
||||
|
||||
static void
|
||||
header_drag_begin (GtkGestureDrag *gesture,
|
||||
double start_x,
|
||||
double start_y,
|
||||
GtkColumnView *self)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
self->drag_pos = -1;
|
||||
|
||||
n = g_list_model_get_n_items (G_LIST_MODEL (self->columns));
|
||||
for (i = 0; !self->in_column_resize && i < n; i++)
|
||||
{
|
||||
GtkColumnViewColumn *column = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
|
||||
|
||||
if (!gtk_column_view_column_get_visible (column))
|
||||
{
|
||||
g_object_unref (column);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i + 1 < n &&
|
||||
gtk_column_view_column_get_resizable (column) &&
|
||||
gtk_column_view_in_resize_rect (self, column, start_x, start_y))
|
||||
{
|
||||
int size;
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
if (!gtk_widget_has_focus (GTK_WIDGET (self)))
|
||||
gtk_widget_grab_focus (GTK_WIDGET (self));
|
||||
|
||||
gtk_column_view_column_get_allocation (column, NULL, &size);
|
||||
gtk_column_view_column_set_fixed_width (column, size);
|
||||
|
||||
self->drag_pos = i;
|
||||
self->drag_x = start_x - size;
|
||||
self->in_column_resize = TRUE;
|
||||
|
||||
g_object_unref (column);
|
||||
break;
|
||||
}
|
||||
|
||||
if (gtk_column_view_column_get_reorderable (column) &&
|
||||
gtk_column_view_in_header (self, column, start_x, start_y))
|
||||
{
|
||||
int pos;
|
||||
|
||||
gtk_column_view_column_get_allocation (column, &pos, NULL);
|
||||
|
||||
self->drag_pos = i;
|
||||
self->drag_offset = start_x - pos;
|
||||
|
||||
g_object_unref (column);
|
||||
break;
|
||||
}
|
||||
|
||||
g_object_unref (column);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
header_drag_end (GtkGestureDrag *gesture,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkColumnView *self)
|
||||
{
|
||||
double start_x, x;
|
||||
|
||||
gtk_gesture_drag_get_start_point (gesture, &start_x, NULL);
|
||||
x = start_x + offset_x;
|
||||
|
||||
remove_autoscroll (self);
|
||||
|
||||
if (self->in_column_resize)
|
||||
{
|
||||
self->in_column_resize = FALSE;
|
||||
}
|
||||
else if (self->in_column_reorder)
|
||||
{
|
||||
GdkEventSequence *sequence;
|
||||
GtkColumnViewColumn *column;
|
||||
GtkWidget *header;
|
||||
int i;
|
||||
|
||||
self->in_column_reorder = FALSE;
|
||||
|
||||
if (self->drag_pos == -1)
|
||||
return;
|
||||
|
||||
column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos);
|
||||
header = gtk_column_view_column_get_header (column);
|
||||
gtk_style_context_remove_class (gtk_widget_get_style_context (header), "dnd");
|
||||
|
||||
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
|
||||
if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
|
||||
return;
|
||||
|
||||
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)); i++)
|
||||
{
|
||||
GtkColumnViewColumn *col = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
|
||||
|
||||
if (gtk_column_view_column_get_visible (col))
|
||||
{
|
||||
int pos, size;
|
||||
|
||||
gtk_column_view_column_get_allocation (col, &pos, &size);
|
||||
if (pos <= x && x <= pos + size)
|
||||
{
|
||||
gtk_column_view_insert_column (self, i, column);
|
||||
g_object_unref (col);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (col);
|
||||
}
|
||||
|
||||
g_object_unref (column);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_column_resize (GtkColumnView *self,
|
||||
double x)
|
||||
{
|
||||
GtkColumnViewColumn *column;
|
||||
|
||||
column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos);
|
||||
gtk_column_view_column_set_fixed_width (column, MAX (x - self->drag_x, 0));
|
||||
g_object_unref (column);
|
||||
}
|
||||
|
||||
static void
|
||||
update_column_reorder (GtkColumnView *self,
|
||||
double x)
|
||||
{
|
||||
GtkColumnViewColumn *column;
|
||||
int width;
|
||||
int size;
|
||||
|
||||
column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos);
|
||||
width = gtk_widget_get_allocated_width (GTK_WIDGET (self->header));
|
||||
gtk_column_view_column_get_allocation (column, NULL, &size);
|
||||
|
||||
self->drag_x = CLAMP (x - self->drag_offset, 0, width - size);
|
||||
|
||||
gtk_widget_queue_allocate (GTK_WIDGET (self));
|
||||
gtk_column_view_column_queue_resize (column);
|
||||
g_object_unref (column);
|
||||
}
|
||||
|
||||
#define SCROLL_EDGE_SIZE 15
|
||||
|
||||
static void
|
||||
header_drag_update (GtkGestureDrag *gesture,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkColumnView *self)
|
||||
{
|
||||
GdkEventSequence *sequence;
|
||||
double start_x, x;
|
||||
|
||||
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
|
||||
if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
|
||||
return;
|
||||
|
||||
if (self->drag_pos == -1)
|
||||
return;
|
||||
|
||||
if (!self->in_column_resize && !self->in_column_reorder)
|
||||
{
|
||||
if (gtk_drag_check_threshold (GTK_WIDGET (self), 0, 0, offset_x, 0))
|
||||
{
|
||||
GtkColumnViewColumn *column;
|
||||
GtkWidget *header;
|
||||
|
||||
column = g_list_model_get_item (G_LIST_MODEL (self->columns), self->drag_pos);
|
||||
header = gtk_column_view_column_get_header (column);
|
||||
|
||||
gtk_widget_insert_after (header, self->header, gtk_widget_get_last_child (self->header));
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (header), "dnd");
|
||||
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
if (!gtk_widget_has_focus (GTK_WIDGET (self)))
|
||||
gtk_widget_grab_focus (GTK_WIDGET (self));
|
||||
|
||||
self->in_column_reorder = TRUE;
|
||||
|
||||
g_object_unref (column);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_gesture_drag_get_start_point (gesture, &start_x, NULL);
|
||||
x = start_x + offset_x;
|
||||
|
||||
if (self->in_column_resize)
|
||||
update_column_resize (self, x);
|
||||
else if (self->in_column_reorder)
|
||||
update_column_reorder (self, x);
|
||||
|
||||
if (self->in_column_resize || self->in_column_reorder)
|
||||
{
|
||||
double value, page_size, upper;
|
||||
|
||||
value = gtk_adjustment_get_value (self->hadjustment);
|
||||
page_size = gtk_adjustment_get_page_size (self->hadjustment);
|
||||
upper = gtk_adjustment_get_upper (self->hadjustment);
|
||||
|
||||
if (x - value < SCROLL_EDGE_SIZE && value > 0)
|
||||
add_autoscroll (self, x, - (SCROLL_EDGE_SIZE - (x - value))/3.0);
|
||||
else if (value + page_size - x < SCROLL_EDGE_SIZE && value + page_size < upper)
|
||||
add_autoscroll (self, x, (SCROLL_EDGE_SIZE - (value + page_size - x))/3.0);
|
||||
else
|
||||
remove_autoscroll (self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
header_motion (GtkEventControllerMotion *controller,
|
||||
double x,
|
||||
double y,
|
||||
GtkColumnView *self)
|
||||
{
|
||||
gboolean cursor_set = FALSE;
|
||||
int i, n;
|
||||
|
||||
n = g_list_model_get_n_items (G_LIST_MODEL (self->columns));
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
GtkColumnViewColumn *column = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
|
||||
|
||||
if (!gtk_column_view_column_get_visible (column))
|
||||
{
|
||||
g_object_unref (column);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i + 1 < n &&
|
||||
gtk_column_view_column_get_resizable (column) &&
|
||||
gtk_column_view_in_resize_rect (self, column, x, y))
|
||||
{
|
||||
gtk_widget_set_cursor_from_name (self->header, "col-resize");
|
||||
cursor_set = TRUE;
|
||||
}
|
||||
|
||||
g_object_unref (column);
|
||||
}
|
||||
|
||||
if (!cursor_set)
|
||||
gtk_widget_set_cursor (self->header, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
header_key_pressed (GtkEventControllerKey *controller,
|
||||
guint keyval,
|
||||
guint keycode,
|
||||
GdkModifierType modifiers,
|
||||
GtkColumnView *self)
|
||||
{
|
||||
if (self->in_column_reorder)
|
||||
{
|
||||
if (keyval == GDK_KEY_Escape)
|
||||
gtk_gesture_set_state (self->drag_gesture, GTK_EVENT_SEQUENCE_DENIED);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_column_view_init (GtkColumnView *self)
|
||||
{
|
||||
GtkEventController *controller;
|
||||
|
||||
self->columns = g_list_store_new (GTK_TYPE_COLUMN_VIEW_COLUMN);
|
||||
|
||||
self->header = gtk_list_item_widget_new (NULL, "header");
|
||||
@@ -517,6 +1000,22 @@ gtk_column_view_init (GtkColumnView *self)
|
||||
gtk_widget_set_layout_manager (self->header, gtk_column_view_layout_new (self));
|
||||
gtk_widget_set_parent (self->header, GTK_WIDGET (self));
|
||||
|
||||
controller = GTK_EVENT_CONTROLLER (gtk_gesture_drag_new ());
|
||||
g_signal_connect (controller, "drag-begin", G_CALLBACK (header_drag_begin), self);
|
||||
g_signal_connect (controller, "drag-update", G_CALLBACK (header_drag_update), self);
|
||||
g_signal_connect (controller, "drag-end", G_CALLBACK (header_drag_end), self);
|
||||
gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
|
||||
gtk_widget_add_controller (self->header, controller);
|
||||
self->drag_gesture = GTK_GESTURE (controller);
|
||||
|
||||
controller = gtk_event_controller_motion_new ();
|
||||
g_signal_connect (controller, "motion", G_CALLBACK (header_motion), self);
|
||||
gtk_widget_add_controller (self->header, controller);
|
||||
|
||||
controller = gtk_event_controller_key_new ();
|
||||
g_signal_connect (controller, "key-pressed", G_CALLBACK (header_key_pressed), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), controller);
|
||||
|
||||
self->sorter = gtk_column_view_sorter_new ();
|
||||
self->factory = gtk_column_list_item_factory_new (self);
|
||||
self->listview = GTK_LIST_VIEW (gtk_list_view_new_with_factory (
|
||||
@@ -530,6 +1029,7 @@ gtk_column_view_init (GtkColumnView *self)
|
||||
g_quark_from_static_string (I_("view")));
|
||||
|
||||
gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN);
|
||||
gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -691,6 +1191,7 @@ gtk_column_view_remove_column (GtkColumnView *self,
|
||||
g_object_unref (item);
|
||||
if (item == column)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
gtk_column_view_sorter_remove_column (GTK_COLUMN_VIEW_SORTER (self->sorter), column);
|
||||
@@ -698,6 +1199,55 @@ gtk_column_view_remove_column (GtkColumnView *self,
|
||||
g_list_store_remove (self->columns, i);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_insert_column:
|
||||
* @self: a #GtkColumnView
|
||||
* @position: the position to insert @column at
|
||||
* @column: the #GtkColumnViewColumn to insert
|
||||
*
|
||||
* Inserts a column at the given position in the columns of @self.
|
||||
*
|
||||
* If @column is already a column of @self, it will be repositioned.
|
||||
*/
|
||||
void
|
||||
gtk_column_view_insert_column (GtkColumnView *self,
|
||||
guint position,
|
||||
GtkColumnViewColumn *column)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLUMN_VIEW (self));
|
||||
g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (column));
|
||||
g_return_if_fail (gtk_column_view_column_get_column_view (column) == NULL ||
|
||||
gtk_column_view_column_get_column_view (column) == self);
|
||||
g_return_if_fail (position <= g_list_model_get_n_items (G_LIST_MODEL (self->columns)));
|
||||
|
||||
g_object_ref (column);
|
||||
|
||||
if (gtk_column_view_column_get_column_view (column) == self)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->columns)); i++)
|
||||
{
|
||||
GtkColumnViewColumn *item = g_list_model_get_item (G_LIST_MODEL (self->columns), i);
|
||||
|
||||
g_object_unref (item);
|
||||
if (item == column)
|
||||
{
|
||||
g_list_store_remove (self->columns, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
gtk_column_view_column_set_column_view (column, self);
|
||||
|
||||
g_list_store_insert (self->columns, position, column);
|
||||
|
||||
gtk_column_view_column_queue_resize (column);
|
||||
|
||||
g_object_unref (column);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_column_view_measure_across (GtkColumnView *self,
|
||||
int *minimum,
|
||||
@@ -732,6 +1282,12 @@ gtk_column_view_get_header_widget (GtkColumnView *self)
|
||||
return GTK_LIST_ITEM_WIDGET (self->header);
|
||||
}
|
||||
|
||||
GtkListView *
|
||||
gtk_column_view_get_list_view (GtkColumnView *self)
|
||||
{
|
||||
return GTK_LIST_VIEW (self->listview);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_get_sorter:
|
||||
* @self: a #GtkColumnView
|
||||
@@ -829,3 +1385,102 @@ gtk_column_view_get_single_click_activate (GtkColumnView *self)
|
||||
|
||||
return gtk_list_view_get_single_click_activate (self->listview);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_set_enable_rubberband:
|
||||
* @self: a #GtkColumnView
|
||||
* @enable_rubberband: %TRUE to enable rubberband selection
|
||||
*
|
||||
* Sets whether selections can be changed by dragging with the mouse.
|
||||
*/
|
||||
void
|
||||
gtk_column_view_set_enable_rubberband (GtkColumnView *self,
|
||||
gboolean enable_rubberband)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLUMN_VIEW (self));
|
||||
|
||||
if (enable_rubberband == gtk_list_view_get_enable_rubberband (self->listview))
|
||||
return;
|
||||
|
||||
gtk_list_view_set_enable_rubberband (self->listview, enable_rubberband);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ENABLE_RUBBERBAND]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_get_enable_rubberband:
|
||||
* @self: a #GtkColumnView
|
||||
*
|
||||
* Returns whether rows can be selected by dragging with the mouse.
|
||||
*
|
||||
* Returns: %TRUE if rubberband selection is enabled
|
||||
*/
|
||||
gboolean
|
||||
gtk_column_view_get_enable_rubberband (GtkColumnView *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COLUMN_VIEW (self), FALSE);
|
||||
|
||||
return gtk_list_view_get_enable_rubberband (self->listview);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_set_search_filter:
|
||||
* @self: a #GtkColumnView
|
||||
* @filter: (nullable): the filter to use for search, or %NULL
|
||||
*
|
||||
* Sets a search filter.
|
||||
*
|
||||
* The selection will be moved to first item matching the
|
||||
* filter whenever the filter changes.
|
||||
*
|
||||
* This can be used with single selection and a string
|
||||
* filter that is connected to a search entry.
|
||||
*/
|
||||
void
|
||||
gtk_column_view_set_search_filter (GtkColumnView *self,
|
||||
GtkFilter *filter)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLUMN_VIEW (self));
|
||||
g_return_if_fail (filter == NULL || GTK_IS_FILTER (filter));
|
||||
|
||||
if (filter == gtk_list_view_get_search_filter (GTK_LIST_VIEW (self->listview)))
|
||||
return;
|
||||
|
||||
gtk_list_view_set_search_filter (GTK_LIST_VIEW (self->listview), filter);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SEARCH_FILTER]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_get_search_filter:
|
||||
* @self: a #GtkColumnView
|
||||
*
|
||||
* Gets the search filter that was set with
|
||||
* gtk_column_view_set_search_filter().
|
||||
*
|
||||
* Returns: (transfer none): The search filter of @self
|
||||
*/
|
||||
GtkFilter *
|
||||
gtk_column_view_get_search_filter (GtkColumnView *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COLUMN_VIEW (self), NULL);
|
||||
|
||||
return gtk_list_view_get_search_filter (GTK_LIST_VIEW (self->listview));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_select_next_match:
|
||||
* @self: a #GtkColumnView
|
||||
* @forward: whether to move forward or back
|
||||
*
|
||||
* Moves the selection to the next item matching the
|
||||
* search filter set with gtk_column_view_set_search_filter().
|
||||
*/
|
||||
void
|
||||
gtk_column_view_select_next_match (GtkColumnView *self,
|
||||
gboolean forward)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLUMN_VIEW (self));
|
||||
|
||||
gtk_list_view_select_next_match (GTK_LIST_VIEW (self->listview), forward);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <gtk/gtktypes.h>
|
||||
#include <gtk/gtksortlistmodel.h>
|
||||
#include <gtk/gtksorter.h>
|
||||
#include <gtk/gtkfilter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -61,6 +62,10 @@ void gtk_column_view_append_column (GtkColumnView
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_remove_column (GtkColumnView *self,
|
||||
GtkColumnViewColumn *column);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_insert_column (GtkColumnView *self,
|
||||
guint position,
|
||||
GtkColumnViewColumn *column);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_column_view_get_model (GtkColumnView *self);
|
||||
@@ -77,6 +82,7 @@ void gtk_column_view_set_show_separators (GtkColumnView
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSorter * gtk_column_view_get_sorter (GtkColumnView *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_sort_by_column (GtkColumnView *self,
|
||||
GtkColumnViewColumn *column,
|
||||
GtkSortType direction);
|
||||
@@ -87,6 +93,22 @@ void gtk_column_view_set_single_click_activate (GtkColumnView
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_column_view_get_single_click_activate (GtkColumnView *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_set_enable_rubberband (GtkColumnView *self,
|
||||
gboolean enable_rubberband);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_column_view_get_enable_rubberband (GtkColumnView *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_set_search_filter (GtkColumnView *self,
|
||||
GtkFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilter * gtk_column_view_get_search_filter (GtkColumnView *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_select_next_match (GtkColumnView *self,
|
||||
gboolean forward);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COLUMN_VIEW_H__ */
|
||||
|
||||
@@ -53,10 +53,18 @@ gtk_column_view_cell_measure (GtkWidget *widget,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GtkColumnViewCell *cell = GTK_COLUMN_VIEW_CELL (widget);
|
||||
GtkWidget *child = gtk_widget_get_first_child (widget);
|
||||
|
||||
if (child)
|
||||
gtk_widget_measure (child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
int fixed_width = gtk_column_view_column_get_fixed_width (cell->column);
|
||||
if (fixed_width > -1)
|
||||
*minimum = *natural = fixed_width;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -156,6 +164,7 @@ gtk_column_view_cell_new (GtkColumnViewColumn *column)
|
||||
|
||||
cell = g_object_new (GTK_TYPE_COLUMN_VIEW_CELL,
|
||||
"factory", gtk_column_view_column_get_factory (column),
|
||||
"visible", gtk_column_view_column_get_visible (column),
|
||||
NULL);
|
||||
|
||||
cell->column = g_object_ref (column);
|
||||
|
||||
+381
-1
@@ -60,6 +60,14 @@ struct _GtkColumnViewColumn
|
||||
int natural_size_request;
|
||||
int allocation_offset;
|
||||
int allocation_size;
|
||||
int header_position;
|
||||
|
||||
int fixed_width;
|
||||
|
||||
guint visible : 1;
|
||||
guint resizable : 1;
|
||||
guint expand : 1;
|
||||
guint reorderable : 1;
|
||||
|
||||
/* This list isn't sorted - this is just caching for performance */
|
||||
GtkColumnViewCell *first_cell; /* no reference, just caching */
|
||||
@@ -77,6 +85,11 @@ enum
|
||||
PROP_FACTORY,
|
||||
PROP_TITLE,
|
||||
PROP_SORTER,
|
||||
PROP_VISIBLE,
|
||||
PROP_RESIZABLE,
|
||||
PROP_EXPAND,
|
||||
PROP_REORDERABLE,
|
||||
PROP_FIXED_WIDTH,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
@@ -126,6 +139,26 @@ gtk_column_view_column_get_property (GObject *object,
|
||||
g_value_set_object (value, self->sorter);
|
||||
break;
|
||||
|
||||
case PROP_VISIBLE:
|
||||
g_value_set_boolean (value, self->visible);
|
||||
break;
|
||||
|
||||
case PROP_RESIZABLE:
|
||||
g_value_set_boolean (value, self->resizable);
|
||||
break;
|
||||
|
||||
case PROP_EXPAND:
|
||||
g_value_set_boolean (value, self->expand);
|
||||
break;
|
||||
|
||||
case PROP_REORDERABLE:
|
||||
g_value_set_boolean (value, self->reorderable);
|
||||
break;
|
||||
|
||||
case PROP_FIXED_WIDTH:
|
||||
g_value_set_int (value, self->fixed_width);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -154,6 +187,26 @@ gtk_column_view_column_set_property (GObject *object,
|
||||
gtk_column_view_column_set_sorter (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_VISIBLE:
|
||||
gtk_column_view_column_set_visible (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_RESIZABLE:
|
||||
gtk_column_view_column_set_resizable (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_EXPAND:
|
||||
gtk_column_view_column_set_expand (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_REORDERABLE:
|
||||
gtk_column_view_column_set_reorderable (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_FIXED_WIDTH:
|
||||
gtk_column_view_column_set_fixed_width (self, g_value_get_int (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -217,6 +270,67 @@ gtk_column_view_column_class_init (GtkColumnViewColumnClass *klass)
|
||||
GTK_TYPE_SORTER,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GtkColumnViewColumn:visible:
|
||||
*
|
||||
* Whether this column is visible
|
||||
*/
|
||||
properties[PROP_VISIBLE] =
|
||||
g_param_spec_boolean ("visible",
|
||||
P_("Visible"),
|
||||
P_("Whether this column is visible"),
|
||||
TRUE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GtkColumnViewColumn:resizable:
|
||||
*
|
||||
* Whether this column is resizable
|
||||
*/
|
||||
properties[PROP_RESIZABLE] =
|
||||
g_param_spec_boolean ("resizable",
|
||||
P_("Resizable"),
|
||||
P_("Whether this column is resizable"),
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GtkColumnViewColumn:expand:
|
||||
*
|
||||
* Column gets share of extra width allocated to the view
|
||||
*/
|
||||
properties[PROP_EXPAND] =
|
||||
g_param_spec_boolean ("expand",
|
||||
P_("Expand"),
|
||||
P_("column gets share of extra width"),
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GtkColumnViewColumn:reorderable:
|
||||
*
|
||||
* Whether this column is reorderable
|
||||
*/
|
||||
properties[PROP_REORDERABLE] =
|
||||
g_param_spec_boolean ("reorderable",
|
||||
P_("Reorderable"),
|
||||
P_("Whether this column is reorderable"),
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GtkColumnViewColumn:fixed-width:
|
||||
*
|
||||
* If not -1, this is the width that the column is allocated,
|
||||
* regardless of the size of its content.
|
||||
*/
|
||||
properties[PROP_FIXED_WIDTH] =
|
||||
g_param_spec_int ("fixed-width",
|
||||
P_("Fixed width"),
|
||||
P_("Fixed width of this column"),
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
@@ -225,6 +339,11 @@ gtk_column_view_column_init (GtkColumnViewColumn *self)
|
||||
{
|
||||
self->minimum_size_request = -1;
|
||||
self->natural_size_request = -1;
|
||||
self->visible = TRUE;
|
||||
self->resizable = FALSE;
|
||||
self->expand = FALSE;
|
||||
self->reorderable = FALSE;
|
||||
self->fixed_width = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -333,6 +452,12 @@ gtk_column_view_column_measure (GtkColumnViewColumn *self,
|
||||
int *minimum,
|
||||
int *natural)
|
||||
{
|
||||
if (self->fixed_width > -1)
|
||||
{
|
||||
self->minimum_size_request = self->fixed_width;
|
||||
self->natural_size_request = self->fixed_width;
|
||||
}
|
||||
|
||||
if (self->minimum_size_request < 0)
|
||||
{
|
||||
GtkColumnViewCell *cell;
|
||||
@@ -375,6 +500,7 @@ gtk_column_view_column_allocate (GtkColumnViewColumn *self,
|
||||
{
|
||||
self->allocation_offset = offset;
|
||||
self->allocation_size = size;
|
||||
self->header_position = offset;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -567,7 +693,7 @@ gtk_column_view_column_set_title (GtkColumnViewColumn *self,
|
||||
*
|
||||
* Returns the title set with gtk_column_view_column_set_title().
|
||||
*
|
||||
* Returns: (nullable) The column's title
|
||||
* Returns: (nullable): The column's title
|
||||
*/
|
||||
const char *
|
||||
gtk_column_view_column_get_title (GtkColumnViewColumn *self)
|
||||
@@ -647,3 +773,257 @@ gtk_column_view_column_notify_sort (GtkColumnViewColumn *self)
|
||||
if (self->header)
|
||||
gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_column_set_visible:
|
||||
* @self: a #GtkColumnViewColumn
|
||||
* @visible: whether this column should be visible
|
||||
*
|
||||
* Sets whether this column should be visible in views.
|
||||
*/
|
||||
void
|
||||
gtk_column_view_column_set_visible (GtkColumnViewColumn *self,
|
||||
gboolean visible)
|
||||
{
|
||||
GtkColumnViewCell *cell;
|
||||
|
||||
g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
|
||||
|
||||
if (self->visible == visible)
|
||||
return;
|
||||
|
||||
self->visible = visible;
|
||||
|
||||
self->minimum_size_request = -1;
|
||||
self->natural_size_request = -1;
|
||||
|
||||
if (self->header)
|
||||
gtk_widget_set_visible (GTK_WIDGET (self->header), visible);
|
||||
|
||||
for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (cell))
|
||||
{
|
||||
gtk_widget_set_visible (GTK_WIDGET (cell), visible);
|
||||
}
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_VISIBLE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_get_visible:
|
||||
* @self: a #GtkColumnViewColumn
|
||||
*
|
||||
* Returns whether this column is visible.
|
||||
*
|
||||
* Returns: %TRUE if this column is visible
|
||||
*/
|
||||
gboolean
|
||||
gtk_column_view_column_get_visible (GtkColumnViewColumn *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), TRUE);
|
||||
|
||||
return self->visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_column_set_resizable:
|
||||
* @self: a #GtkColumnViewColumn
|
||||
* @resizable: whether this column should be resizable
|
||||
*
|
||||
* Sets whether this column should be resizable by dragging.
|
||||
*/
|
||||
void
|
||||
gtk_column_view_column_set_resizable (GtkColumnViewColumn *self,
|
||||
gboolean resizable)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
|
||||
|
||||
if (self->resizable == resizable)
|
||||
return;
|
||||
|
||||
self->resizable = resizable;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_RESIZABLE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_get_resizable:
|
||||
* @self: a #GtkColumnView
|
||||
*
|
||||
* Returns whether this column is resizable.
|
||||
*
|
||||
* Returns: %TRUE if this column is resizable
|
||||
*/
|
||||
gboolean
|
||||
gtk_column_view_column_get_resizable (GtkColumnViewColumn *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), TRUE);
|
||||
|
||||
return self->resizable;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_column_set_expand:
|
||||
* @self: a #GtkColumnViewColumn
|
||||
* @expand: %TRUE if this column should expand to fill available sace
|
||||
*
|
||||
* Sets the column to take available extra space.
|
||||
*
|
||||
* The extra space is shared equally amongst all columns that
|
||||
* have the expand set to %TRUE.
|
||||
*/
|
||||
void
|
||||
gtk_column_view_column_set_expand (GtkColumnViewColumn *self,
|
||||
gboolean expand)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
|
||||
|
||||
if (self->expand == expand)
|
||||
return;
|
||||
|
||||
self->expand = expand;
|
||||
|
||||
if (self->visible && self->view)
|
||||
gtk_widget_queue_resize (GTK_WIDGET (self->view));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_EXPAND]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_get_expand:
|
||||
* @self: a #GtkColumnViewColumn
|
||||
*
|
||||
* Returns whether this column should expand.
|
||||
*
|
||||
* Returns: %TRUE if this column expands
|
||||
*/
|
||||
gboolean
|
||||
gtk_column_view_column_get_expand (GtkColumnViewColumn *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), TRUE);
|
||||
|
||||
return self->expand;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_column_set_reorderable:
|
||||
* @self: a #GtkColumnViewColumn
|
||||
* @reorderable: whether this column should be reorderable
|
||||
*
|
||||
* Sets whether this column should be reorderable by dragging.
|
||||
*/
|
||||
void
|
||||
gtk_column_view_column_set_reorderable (GtkColumnViewColumn *self,
|
||||
gboolean reorderable)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
|
||||
|
||||
if (self->reorderable == reorderable)
|
||||
return;
|
||||
|
||||
self->reorderable = reorderable;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_REORDERABLE]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_get_reorderable:
|
||||
* @self: a #GtkColumnView
|
||||
*
|
||||
* Returns whether this column is reorderable.
|
||||
*
|
||||
* Returns: %TRUE if this column is reorderable
|
||||
*/
|
||||
gboolean
|
||||
gtk_column_view_column_get_reorderable (GtkColumnViewColumn *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), TRUE);
|
||||
|
||||
return self->reorderable;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_column_set_fixed_width:
|
||||
* @self: a #GtkColumnViewColumn
|
||||
* @fixed_width: the new fixed width, or -1
|
||||
*
|
||||
* If @fixed_width is not -1, sets the fixed width of @column;
|
||||
* otherwise unsets it.
|
||||
*
|
||||
* Setting a fixed width overrides the automatically calculated
|
||||
* width. Interactive resizing also sets the “fixed-width” property.
|
||||
*/
|
||||
void
|
||||
gtk_column_view_column_set_fixed_width (GtkColumnViewColumn *self,
|
||||
int fixed_width)
|
||||
{
|
||||
GtkOverflow overflow;
|
||||
|
||||
g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
|
||||
g_return_if_fail (fixed_width >= -1);
|
||||
|
||||
if (self->fixed_width == fixed_width)
|
||||
return;
|
||||
|
||||
self->fixed_width = fixed_width;
|
||||
|
||||
if (fixed_width > -1)
|
||||
overflow = GTK_OVERFLOW_HIDDEN;
|
||||
else
|
||||
overflow = GTK_OVERFLOW_VISIBLE;
|
||||
|
||||
if (self->header &&
|
||||
overflow != gtk_widget_get_overflow (GTK_WIDGET (self->header)))
|
||||
{
|
||||
GtkColumnViewCell *cell;
|
||||
|
||||
gtk_widget_set_overflow (GTK_WIDGET (self->header), overflow);
|
||||
|
||||
for (cell = self->first_cell; cell; cell = gtk_column_view_cell_get_next (cell))
|
||||
gtk_widget_set_overflow (GTK_WIDGET (cell), overflow);
|
||||
}
|
||||
|
||||
gtk_column_view_column_queue_resize (self);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FIXED_WIDTH]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_column_get_fixed_width:
|
||||
* @self: a #GtkColumnViewColumn
|
||||
*
|
||||
* Gets the fixed width of the column.
|
||||
*
|
||||
* Returns: the fixed with of the column
|
||||
*/
|
||||
int
|
||||
gtk_column_view_column_get_fixed_width (GtkColumnViewColumn *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), -1);
|
||||
|
||||
return self->fixed_width;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_column_view_column_get_header (GtkColumnViewColumn *self)
|
||||
{
|
||||
return self->header;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_column_view_column_set_header_position (GtkColumnViewColumn *self,
|
||||
int offset)
|
||||
{
|
||||
self->header_position = offset;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_column_view_column_get_header_allocation (GtkColumnViewColumn *self,
|
||||
int *offset,
|
||||
int *size)
|
||||
{
|
||||
if (offset)
|
||||
*offset = self->header_position;
|
||||
|
||||
if (size)
|
||||
*size = self->allocation_size;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,36 @@ void gtk_column_view_column_set_sorter (GtkColu
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkSorter * gtk_column_view_column_get_sorter (GtkColumnViewColumn *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_column_set_visible (GtkColumnViewColumn *self,
|
||||
gboolean visible);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_column_view_column_get_visible (GtkColumnViewColumn *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_column_set_fixed_width (GtkColumnViewColumn *self,
|
||||
int fixed_width);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
int gtk_column_view_column_get_fixed_width (GtkColumnViewColumn *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_column_set_resizable (GtkColumnViewColumn *self,
|
||||
gboolean resizable);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_column_view_column_get_resizable (GtkColumnViewColumn *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_column_set_expand (GtkColumnViewColumn *self,
|
||||
gboolean expand);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_column_view_column_get_expand (GtkColumnViewColumn *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_column_set_reorderable (GtkColumnViewColumn *self,
|
||||
gboolean reorderable);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_column_view_column_get_reorderable (GtkColumnViewColumn *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COLUMN_VIEW_COLUMN_H__ */
|
||||
|
||||
@@ -33,6 +33,7 @@ void gtk_column_view_column_add_cell (GtkColu
|
||||
void gtk_column_view_column_remove_cell (GtkColumnViewColumn *self,
|
||||
GtkColumnViewCell *cell);
|
||||
GtkColumnViewCell * gtk_column_view_column_get_first_cell (GtkColumnViewColumn *self);
|
||||
GtkWidget * gtk_column_view_column_get_header (GtkColumnViewColumn *self);
|
||||
|
||||
void gtk_column_view_column_queue_resize (GtkColumnViewColumn *self);
|
||||
void gtk_column_view_column_measure (GtkColumnViewColumn *self,
|
||||
@@ -47,4 +48,10 @@ void gtk_column_view_column_get_allocation (GtkColu
|
||||
|
||||
void gtk_column_view_column_notify_sort (GtkColumnViewColumn *self);
|
||||
|
||||
void gtk_column_view_column_set_header_position (GtkColumnViewColumn *self,
|
||||
int offset);
|
||||
void gtk_column_view_column_get_header_allocation (GtkColumnViewColumn *self,
|
||||
int *offset,
|
||||
int *size);
|
||||
|
||||
#endif /* __GTK_COLUMN_VIEW_COLUMN_PRIVATE_H__ */
|
||||
|
||||
@@ -118,11 +118,16 @@ gtk_column_view_layout_allocate (GtkLayoutManager *layout_manager,
|
||||
int col_x, col_width;
|
||||
|
||||
if (GTK_IS_COLUMN_VIEW_CELL (child))
|
||||
column = gtk_column_view_cell_get_column (GTK_COLUMN_VIEW_CELL (child));
|
||||
{
|
||||
column = gtk_column_view_cell_get_column (GTK_COLUMN_VIEW_CELL (child));
|
||||
gtk_column_view_column_get_allocation (column, &col_x, &col_width);
|
||||
}
|
||||
else
|
||||
column = gtk_column_view_title_get_column (GTK_COLUMN_VIEW_TITLE (child));
|
||||
{
|
||||
column = gtk_column_view_title_get_column (GTK_COLUMN_VIEW_TITLE (child));
|
||||
gtk_column_view_column_get_header_allocation (column, &col_x, &col_width);
|
||||
}
|
||||
|
||||
gtk_column_view_column_get_allocation (column, &col_x, &col_width);
|
||||
gtk_widget_size_allocate (child, &(GtkAllocation) { col_x, 0, col_width, height }, baseline);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,13 @@
|
||||
#define __GTK_COLUMN_VIEW_PRIVATE_H__
|
||||
|
||||
#include "gtk/gtkcolumnview.h"
|
||||
#include "gtk/gtklistview.h"
|
||||
|
||||
#include "gtk/gtkcolumnviewsorterprivate.h"
|
||||
#include "gtk/gtklistitemwidgetprivate.h"
|
||||
|
||||
GtkListItemWidget * gtk_column_view_get_header_widget (GtkColumnView *self);
|
||||
GtkListView * gtk_column_view_get_list_view (GtkColumnView *self);
|
||||
|
||||
void gtk_column_view_measure_across (GtkColumnView *self,
|
||||
int *minimum,
|
||||
|
||||
@@ -58,10 +58,18 @@ gtk_column_view_title_measure (GtkWidget *widget,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (widget);
|
||||
GtkWidget *child = gtk_widget_get_first_child (widget);
|
||||
|
||||
if (child)
|
||||
gtk_widget_measure (child, orientation, for_size, minimum, natural, minimum_baseline, natural_baseline);
|
||||
|
||||
if (orientation == GTK_ORIENTATION_HORIZONTAL)
|
||||
{
|
||||
int fixed_width = gtk_column_view_column_get_fixed_width (self->column);
|
||||
if (fixed_width > -1)
|
||||
*minimum = *natural = fixed_width;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -112,11 +120,11 @@ gtk_column_view_title_resize_func (GtkWidget *widget)
|
||||
}
|
||||
|
||||
static void
|
||||
click_pressed_cb (GtkGestureClick *gesture,
|
||||
guint n_press,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
GtkWidget *widget)
|
||||
click_released_cb (GtkGestureClick *gesture,
|
||||
guint n_press,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (widget);
|
||||
GtkSorter *sorter;
|
||||
@@ -150,7 +158,7 @@ gtk_column_view_title_init (GtkColumnViewTitle *self)
|
||||
gtk_box_append (GTK_BOX (self->box), self->sort);
|
||||
|
||||
gesture = gtk_gesture_click_new ();
|
||||
g_signal_connect (gesture, "pressed", G_CALLBACK (click_pressed_cb), self);
|
||||
g_signal_connect (gesture, "released", G_CALLBACK (click_released_cb), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,704 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* 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: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkcoverflow.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtklistbaseprivate.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkorientable.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkrbtreeprivate.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
/* Extra items to display at most above + below the central item */
|
||||
#define GTK_COVER_FLOW_DISPLAY_ITEMS 5
|
||||
|
||||
/* Number of extra space we leave around the covers */
|
||||
#define GTK_COVER_FLOW_SCALE_ALONG 3
|
||||
#define GTK_COVER_FLOW_SCALE_ACROSS 2
|
||||
|
||||
/**
|
||||
* SECTION:gtkcoverflow
|
||||
* @title: GtkCoverFlow
|
||||
* @short_description: A coverflow list widget
|
||||
* @see_also: #GListModel
|
||||
*
|
||||
* GtkCoverFlow is a widget to present a coverflow list
|
||||
*/
|
||||
|
||||
struct _GtkCoverFlow
|
||||
{
|
||||
GtkListBase parent_instance;
|
||||
|
||||
int size_across;
|
||||
int size_along;
|
||||
};
|
||||
|
||||
struct _GtkCoverFlowClass
|
||||
{
|
||||
GtkListBaseClass parent_class;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_FACTORY,
|
||||
PROP_MODEL,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
enum {
|
||||
ACTIVATE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkCoverFlow, gtk_cover_flow, GTK_TYPE_LIST_BASE)
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static gboolean
|
||||
gtk_cover_flow_get_allocation_along (GtkListBase *base,
|
||||
guint pos,
|
||||
int *offset,
|
||||
int *size)
|
||||
{
|
||||
GtkCoverFlow *self = GTK_COVER_FLOW (base);
|
||||
|
||||
if (offset)
|
||||
*offset = pos * self->size_along;
|
||||
if (size)
|
||||
*size = self->size_along;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_cover_flow_get_allocation_across (GtkListBase *base,
|
||||
guint pos,
|
||||
int *offset,
|
||||
int *size)
|
||||
{
|
||||
GtkCoverFlow *self = GTK_COVER_FLOW (base);
|
||||
|
||||
if (offset)
|
||||
*offset = pos * self->size_across;
|
||||
if (size)
|
||||
*size = self->size_across;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_cover_flow_move_focus_along (GtkListBase *base,
|
||||
guint pos,
|
||||
int steps)
|
||||
{
|
||||
if (steps < 0)
|
||||
return pos - MIN (pos, -steps);
|
||||
else
|
||||
{
|
||||
pos += MIN (gtk_list_base_get_n_items (base) - pos - 1, steps);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_cover_flow_move_focus_across (GtkListBase *base,
|
||||
guint pos,
|
||||
int steps)
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_cover_flow_get_position_from_allocation (GtkListBase *base,
|
||||
int across,
|
||||
int along,
|
||||
guint *pos,
|
||||
cairo_rectangle_int_t *area)
|
||||
{
|
||||
GtkCoverFlow *self = GTK_COVER_FLOW (base);
|
||||
|
||||
if (across >= self->size_across ||
|
||||
along >= self->size_along * gtk_list_base_get_n_items (base))
|
||||
return FALSE;
|
||||
|
||||
*pos = along / self->size_along;
|
||||
|
||||
if (area)
|
||||
{
|
||||
area->x = 0;
|
||||
area->width = self->size_across;
|
||||
area->y = *pos * self->size_along;
|
||||
area->height = self->size_along;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_measure_children (GtkCoverFlow *self,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural)
|
||||
{
|
||||
GtkListItemManagerItem *item;
|
||||
int min, nat, child_min, child_nat;
|
||||
|
||||
min = 0;
|
||||
nat = 0;
|
||||
|
||||
for (item = gtk_list_item_manager_get_first (gtk_list_base_get_manager (GTK_LIST_BASE (self)));
|
||||
item != NULL;
|
||||
item = gtk_rb_tree_node_get_next (item))
|
||||
{
|
||||
/* ignore unavailable items */
|
||||
if (item->widget == NULL)
|
||||
continue;
|
||||
|
||||
gtk_widget_measure (item->widget,
|
||||
orientation, for_size,
|
||||
&child_min, &child_nat, NULL, NULL);
|
||||
min = MAX (min, child_min);
|
||||
nat = MAX (nat, child_nat);
|
||||
}
|
||||
|
||||
*minimum = min;
|
||||
*natural = nat;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_measure_across (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural)
|
||||
{
|
||||
GtkCoverFlow *self = GTK_COVER_FLOW (widget);
|
||||
|
||||
if (for_size > 0)
|
||||
for_size /= GTK_COVER_FLOW_SCALE_ALONG;
|
||||
|
||||
gtk_cover_flow_measure_children (self, orientation, for_size, minimum, natural);
|
||||
|
||||
*minimum *= GTK_COVER_FLOW_SCALE_ACROSS;
|
||||
*natural *= GTK_COVER_FLOW_SCALE_ACROSS;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_measure_along (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural)
|
||||
{
|
||||
GtkCoverFlow *self = GTK_COVER_FLOW (widget);
|
||||
|
||||
if (for_size > 0)
|
||||
for_size /= GTK_COVER_FLOW_SCALE_ACROSS;
|
||||
|
||||
gtk_cover_flow_measure_children (self, orientation, for_size, minimum, natural);
|
||||
|
||||
*minimum *= GTK_COVER_FLOW_SCALE_ALONG;
|
||||
*natural *= GTK_COVER_FLOW_SCALE_ALONG;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_measure (GtkWidget *widget,
|
||||
GtkOrientation orientation,
|
||||
int for_size,
|
||||
int *minimum,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline)
|
||||
{
|
||||
GtkCoverFlow *self = GTK_COVER_FLOW (widget);
|
||||
|
||||
if (orientation == gtk_list_base_get_orientation (GTK_LIST_BASE (self)))
|
||||
gtk_cover_flow_measure_along (widget, orientation, for_size, minimum, natural);
|
||||
else
|
||||
gtk_cover_flow_measure_across (widget, orientation, for_size, minimum, natural);
|
||||
}
|
||||
|
||||
static GskTransform *
|
||||
transform_translate_oriented (GskTransform *transform,
|
||||
GtkOrientation orientation,
|
||||
GtkTextDirection dir,
|
||||
float across,
|
||||
float along)
|
||||
{
|
||||
if (orientation == GTK_ORIENTATION_VERTICAL)
|
||||
return gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (across, along));
|
||||
else if (dir == GTK_TEXT_DIR_LTR)
|
||||
return gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (along, across));
|
||||
else
|
||||
return gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (-along, across));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_size_allocate_child (GtkWidget *child,
|
||||
GtkOrientation orientation,
|
||||
GtkTextDirection dir,
|
||||
GskTransform *transform,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
if (orientation == GTK_ORIENTATION_VERTICAL)
|
||||
{
|
||||
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (-width / 2, -height / 2));
|
||||
gtk_widget_allocate (child, width, height, -1, transform);
|
||||
}
|
||||
else
|
||||
{
|
||||
transform = gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (-height / 2, -width / 2));
|
||||
gtk_widget_allocate (child, height, width, -1, transform);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
GtkCoverFlow *self = GTK_COVER_FLOW (widget);
|
||||
GtkOrientation orientation, opposite_orientation;
|
||||
GtkTextDirection dir;
|
||||
GtkListItemManagerItem *item;
|
||||
GtkListItemManager *manager;
|
||||
guint i, pos;
|
||||
int x, y, along, across;
|
||||
|
||||
manager = gtk_list_base_get_manager (GTK_LIST_BASE (self));
|
||||
orientation = gtk_list_base_get_orientation (GTK_LIST_BASE (self));
|
||||
opposite_orientation = OPPOSITE_ORIENTATION (orientation);
|
||||
|
||||
/* step 0: exit early if list is empty */
|
||||
if (gtk_list_item_manager_get_root (manager) == NULL)
|
||||
return;
|
||||
|
||||
/* step 1: determine size of children */
|
||||
along = orientation == GTK_ORIENTATION_HORIZONTAL ? width : height;
|
||||
across = opposite_orientation == GTK_ORIENTATION_HORIZONTAL ? width : height;
|
||||
self->size_along = along / GTK_COVER_FLOW_SCALE_ALONG;
|
||||
self->size_across = across / GTK_COVER_FLOW_SCALE_ACROSS;
|
||||
|
||||
/* step 2: update the adjustments */
|
||||
gtk_list_base_update_adjustments (GTK_LIST_BASE (self),
|
||||
self->size_across,
|
||||
self->size_along * gtk_list_base_get_n_items (GTK_LIST_BASE (self)),
|
||||
self->size_across,
|
||||
self->size_along,
|
||||
&x, &y);
|
||||
pos = gtk_list_base_get_anchor (GTK_LIST_BASE (self));
|
||||
|
||||
/* step 4: actually allocate the widgets */
|
||||
dir = _gtk_widget_get_direction (widget);
|
||||
i = 0;
|
||||
|
||||
for (item = gtk_list_item_manager_get_first (manager);
|
||||
item != NULL;
|
||||
item = gtk_rb_tree_node_get_next (item))
|
||||
{
|
||||
if (item->widget)
|
||||
{
|
||||
/* start at the center */
|
||||
GskTransform *transform = transform_translate_oriented (NULL, orientation, dir, across / 2, along / 2);
|
||||
|
||||
if (i == pos)
|
||||
{
|
||||
/* nothing to do, we're already centered */
|
||||
}
|
||||
else if (MAX (pos, i) - MIN (pos, i) < GTK_COVER_FLOW_DISPLAY_ITEMS) /* ABS() doesn't work with guint */
|
||||
{
|
||||
int diff = i - pos;
|
||||
transform = gsk_transform_perspective (transform, MAX (width, height) * 2);
|
||||
transform = transform_translate_oriented (transform,
|
||||
orientation, dir,
|
||||
0,
|
||||
diff * self->size_along / 4);
|
||||
transform = transform_translate_oriented (transform,
|
||||
orientation, dir,
|
||||
0,
|
||||
(diff < 0 ? -1 : 1) * self->size_along / 2);
|
||||
if (orientation == GTK_ORIENTATION_VERTICAL)
|
||||
transform = gsk_transform_rotate_3d (transform,
|
||||
diff > 0 ? 60 : -60,
|
||||
graphene_vec3_x_axis ());
|
||||
else
|
||||
transform = gsk_transform_rotate_3d (transform,
|
||||
diff < 0 ? 60 : -60,
|
||||
graphene_vec3_y_axis ());
|
||||
transform = transform_translate_oriented (transform,
|
||||
orientation, dir,
|
||||
0,
|
||||
(diff < 0 ? 1 : -1) * self->size_along / 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
transform = transform_translate_oriented (transform,
|
||||
orientation, dir,
|
||||
- 2 * self->size_across,
|
||||
- 2 * self->size_along);
|
||||
}
|
||||
gtk_cover_flow_size_allocate_child (item->widget,
|
||||
orientation, dir,
|
||||
transform,
|
||||
self->size_across,
|
||||
self->size_along);
|
||||
}
|
||||
|
||||
i += item->n_items;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkListBase *base = GTK_LIST_BASE (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_FACTORY:
|
||||
g_value_set_object (value, gtk_list_item_manager_get_factory (gtk_list_base_get_manager (base)));
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
g_value_set_object (value, gtk_list_base_get_model (base));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkWidget *child;
|
||||
GtkListItemManagerItem *item;
|
||||
|
||||
item = gtk_list_item_manager_get_nth (gtk_list_base_get_manager (GTK_LIST_BASE (widget)),
|
||||
gtk_list_base_get_anchor (GTK_LIST_BASE (widget)),
|
||||
NULL);
|
||||
if (item == NULL || item->widget == NULL)
|
||||
{
|
||||
GTK_WIDGET_CLASS (gtk_cover_flow_parent_class)->snapshot (widget, snapshot);
|
||||
return;
|
||||
}
|
||||
|
||||
for (child = _gtk_widget_get_first_child (widget);
|
||||
child != item->widget;
|
||||
child = _gtk_widget_get_next_sibling (child))
|
||||
gtk_widget_snapshot_child (widget, child, snapshot);
|
||||
|
||||
for (child = _gtk_widget_get_last_child (widget);
|
||||
child != item->widget;
|
||||
child = _gtk_widget_get_prev_sibling (child))
|
||||
gtk_widget_snapshot_child (widget, child, snapshot);
|
||||
|
||||
gtk_widget_snapshot_child (widget, item->widget, snapshot);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkCoverFlow *self = GTK_COVER_FLOW (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_FACTORY:
|
||||
gtk_cover_flow_set_factory (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_MODEL:
|
||||
gtk_cover_flow_set_model (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_activate_item (GtkWidget *widget,
|
||||
const char *action_name,
|
||||
GVariant *parameter)
|
||||
{
|
||||
GtkCoverFlow *self = GTK_COVER_FLOW (widget);
|
||||
guint pos;
|
||||
|
||||
if (!g_variant_check_format_string (parameter, "u", FALSE))
|
||||
return;
|
||||
|
||||
g_variant_get (parameter, "u", &pos);
|
||||
if (pos >= gtk_list_base_get_n_items (GTK_LIST_BASE (self)))
|
||||
return;
|
||||
|
||||
g_signal_emit (widget, signals[ACTIVATE], 0, pos);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_class_init (GtkCoverFlowClass *klass)
|
||||
{
|
||||
GtkListBaseClass *list_base_class = GTK_LIST_BASE_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
list_base_class->list_item_name = "cover";
|
||||
list_base_class->list_item_size = sizeof (GtkListItemManagerItem);
|
||||
list_base_class->list_item_augment_size = sizeof (GtkListItemManagerItemAugment);
|
||||
list_base_class->list_item_augment_func = gtk_list_item_manager_augment_node;
|
||||
list_base_class->get_allocation_along = gtk_cover_flow_get_allocation_along;
|
||||
list_base_class->get_allocation_across = gtk_cover_flow_get_allocation_across;
|
||||
list_base_class->get_position_from_allocation = gtk_cover_flow_get_position_from_allocation;
|
||||
list_base_class->move_focus_along = gtk_cover_flow_move_focus_along;
|
||||
list_base_class->move_focus_across = gtk_cover_flow_move_focus_across;
|
||||
|
||||
widget_class->measure = gtk_cover_flow_measure;
|
||||
widget_class->size_allocate = gtk_cover_flow_size_allocate;
|
||||
widget_class->snapshot = gtk_cover_flow_snapshot;
|
||||
|
||||
gobject_class->get_property = gtk_cover_flow_get_property;
|
||||
gobject_class->set_property = gtk_cover_flow_set_property;
|
||||
|
||||
/**
|
||||
* GtkCoverFlow:factory:
|
||||
*
|
||||
* Factory for populating list items
|
||||
*/
|
||||
properties[PROP_FACTORY] =
|
||||
g_param_spec_object ("factory",
|
||||
P_("Factory"),
|
||||
P_("Factory for populating list items"),
|
||||
GTK_TYPE_LIST_ITEM_FACTORY,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* GtkCoverFlow:model:
|
||||
*
|
||||
* Model for the items displayed
|
||||
*/
|
||||
properties[PROP_MODEL] =
|
||||
g_param_spec_object ("model",
|
||||
P_("Model"),
|
||||
P_("Model for the items displayed"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
|
||||
/**
|
||||
* GtkCoverFlow::activate:
|
||||
* @self: The #GtkCoverFlow
|
||||
* @position: position of item to activate
|
||||
*
|
||||
* The ::activate signal is emitted when an item has been activated by the user,
|
||||
* usually via activating the GtkCoverFlow|list.activate-item action.
|
||||
*
|
||||
* This allows for a convenient way to handle activation in a listview.
|
||||
* See gtk_list_item_set_activatable() for details on how to use this signal.
|
||||
*/
|
||||
signals[ACTIVATE] =
|
||||
g_signal_new (I_("activate"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__UINT,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_UINT);
|
||||
g_signal_set_va_marshaller (signals[ACTIVATE],
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
g_cclosure_marshal_VOID__UINTv);
|
||||
|
||||
/**
|
||||
* GtkCoverFlow|list.activate-item:
|
||||
* @position: position of item to activate
|
||||
*
|
||||
* Activates the item given in @position by emitting the GtkCoverFlow::activate
|
||||
* signal.
|
||||
*/
|
||||
gtk_widget_class_install_action (widget_class,
|
||||
"list.activate-item",
|
||||
"u",
|
||||
gtk_cover_flow_activate_item);
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, I_("coverflow"));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cover_flow_init (GtkCoverFlow *self)
|
||||
{
|
||||
gtk_list_base_set_anchor_max_widgets (GTK_LIST_BASE (self),
|
||||
0,
|
||||
GTK_COVER_FLOW_DISPLAY_ITEMS);
|
||||
|
||||
/* FIXME: this should overwrite the property default, but gobject properties... */
|
||||
gtk_orientable_set_orientation (GTK_ORIENTABLE (self), GTK_ORIENTATION_HORIZONTAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_cover_flow_new:
|
||||
*
|
||||
* Creates a new empty #GtkCoverFlow.
|
||||
*
|
||||
* You most likely want to call gtk_cover_flow_set_factory() to
|
||||
* set up a way to map its items to widgets and gtk_cover_flow_set_model()
|
||||
* to set a model to provide items next.
|
||||
*
|
||||
* Returns: a new #GtkCoverFlow
|
||||
**/
|
||||
GtkWidget *
|
||||
gtk_cover_flow_new (void)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_COVER_FLOW, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_cover_flow_new_with_factory:
|
||||
* @factory: (transfer full): The factory to populate items with
|
||||
*
|
||||
* Creates a new #GtkCoverFlow that uses the given @factory for
|
||||
* mapping items to widgets.
|
||||
*
|
||||
* You most likely want to call gtk_cover_flow_set_model() to set
|
||||
* a model next.
|
||||
*
|
||||
* The function takes ownership of the
|
||||
* argument, so you can write code like
|
||||
* ```
|
||||
* cover_flow = gtk_cover_flow_new_with_factory (
|
||||
* gtk_builder_list_item_factory_newfrom_resource ("/resource.ui"));
|
||||
* ```
|
||||
*
|
||||
* Returns: a new #GtkCoverFlow using the given @factory
|
||||
**/
|
||||
GtkWidget *
|
||||
gtk_cover_flow_new_with_factory (GtkListItemFactory *factory)
|
||||
{
|
||||
GtkWidget *result;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_LIST_ITEM_FACTORY (factory), NULL);
|
||||
|
||||
result = g_object_new (GTK_TYPE_COVER_FLOW,
|
||||
"factory", factory,
|
||||
NULL);
|
||||
|
||||
g_object_unref (factory);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_cover_flow_get_model:
|
||||
* @self: a #GtkCoverFlow
|
||||
*
|
||||
* Gets the model that's currently used to read the items displayed.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): The model in use
|
||||
**/
|
||||
GListModel *
|
||||
gtk_cover_flow_get_model (GtkCoverFlow *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COVER_FLOW (self), NULL);
|
||||
|
||||
return gtk_list_base_get_model (GTK_LIST_BASE (self));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_cover_flow_set_model:
|
||||
* @self: a #GtkCoverFlow
|
||||
* @model: (allow-none) (transfer none): the model to use or %NULL for none
|
||||
*
|
||||
* Sets the #GListModel to use.
|
||||
*
|
||||
* If the @model is a #GtkSelectionModel, it is used for managing the selection.
|
||||
* Otherwise, @self creates a #GtkSingleSelection for the selection.
|
||||
**/
|
||||
void
|
||||
gtk_cover_flow_set_model (GtkCoverFlow *self,
|
||||
GListModel *model)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COVER_FLOW (self));
|
||||
g_return_if_fail (model == NULL || G_IS_LIST_MODEL (model));
|
||||
|
||||
if (!gtk_list_base_set_model (GTK_LIST_BASE (self), model))
|
||||
return;
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_MODEL]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_cover_flow_get_factory:
|
||||
* @self: a #GtkCoverFlow
|
||||
*
|
||||
* Gets the factory that's currently used to populate list items.
|
||||
*
|
||||
* Returns: (nullable) (transfer none): The factory in use
|
||||
**/
|
||||
GtkListItemFactory *
|
||||
gtk_cover_flow_get_factory (GtkCoverFlow *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COVER_FLOW (self), NULL);
|
||||
|
||||
return gtk_list_item_manager_get_factory (gtk_list_base_get_manager (GTK_LIST_BASE (self)));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_cover_flow_set_factory:
|
||||
* @self: a #GtkCoverFlow
|
||||
* @factory: (allow-none) (transfer none): the factory to use or %NULL for none
|
||||
*
|
||||
* Sets the #GtkListItemFactory to use for populating list items.
|
||||
**/
|
||||
void
|
||||
gtk_cover_flow_set_factory (GtkCoverFlow *self,
|
||||
GtkListItemFactory *factory)
|
||||
{
|
||||
GtkListItemManager *manager;
|
||||
|
||||
g_return_if_fail (GTK_IS_COVER_FLOW (self));
|
||||
g_return_if_fail (factory == NULL || GTK_LIST_ITEM_FACTORY (factory));
|
||||
|
||||
manager = gtk_list_base_get_manager (GTK_LIST_BASE (self));
|
||||
|
||||
if (factory == gtk_list_item_manager_get_factory (manager))
|
||||
return;
|
||||
|
||||
gtk_list_item_manager_set_factory (manager, factory);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FACTORY]);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018 Benjamin Otte
|
||||
*
|
||||
* 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: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_COVER_FLOW_H__
|
||||
#define __GTK_COVER_FLOW_H__
|
||||
|
||||
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gtk/gtk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
#include <gtk/gtklistbase.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_COVER_FLOW (gtk_cover_flow_get_type ())
|
||||
#define GTK_COVER_FLOW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_COVER_FLOW, GtkCoverFlow))
|
||||
#define GTK_COVER_FLOW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_COVER_FLOW, GtkCoverFlowClass))
|
||||
#define GTK_IS_COVER_FLOW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_COVER_FLOW))
|
||||
#define GTK_IS_COVER_FLOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_COVER_FLOW))
|
||||
#define GTK_COVER_FLOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_COVER_FLOW, GtkCoverFlowClass))
|
||||
|
||||
/**
|
||||
* GtkCoverFlow:
|
||||
*
|
||||
* GtkCoverFlow is the simple list implementation for GTK's list widgets.
|
||||
*/
|
||||
typedef struct _GtkCoverFlow GtkCoverFlow;
|
||||
typedef struct _GtkCoverFlowClass GtkCoverFlowClass;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gtk_cover_flow_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget * gtk_cover_flow_new (void);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget * gtk_cover_flow_new_with_factory (GtkListItemFactory *factory);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_cover_flow_get_model (GtkCoverFlow *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_cover_flow_set_model (GtkCoverFlow *self,
|
||||
GListModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_cover_flow_set_factory (GtkCoverFlow *self,
|
||||
GtkListItemFactory *factory);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkListItemFactory *
|
||||
gtk_cover_flow_get_factory (GtkCoverFlow *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_COVER_FLOW_H__ */
|
||||
@@ -40,11 +40,6 @@
|
||||
#include "gtkcssvalueprivate.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
|
||||
/* this is in case round() is not provided by the compiler,
|
||||
* such as in the case of C89 compilers, like MSVC
|
||||
*/
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/*** PARSING ***/
|
||||
|
||||
static gboolean
|
||||
|
||||
@@ -30,11 +30,6 @@
|
||||
#include "gtkprivatetypebuiltins.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
/* this is in case round() is not provided by the compiler,
|
||||
* such as in the case of C89 compilers, like MSVC
|
||||
*/
|
||||
#include "fallback-c89.c"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ANIMATED,
|
||||
|
||||
@@ -29,11 +29,6 @@
|
||||
#include "gtkintl.h"
|
||||
#include "gtkprivatetypebuiltins.h"
|
||||
|
||||
/* this is in case round() is not provided by the compiler,
|
||||
* such as in the case of C89 compilers, like MSVC
|
||||
*/
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/* the actual parsers we have */
|
||||
#include "gtkcssarrayvalueprivate.h"
|
||||
#include "gtkcssbgsizevalueprivate.h"
|
||||
|
||||
@@ -75,8 +75,6 @@
|
||||
#include <cairo-gobject.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtkentry
|
||||
* @Short_description: A single line text entry field
|
||||
|
||||
+2
-2
@@ -980,10 +980,10 @@ gtk_closure_expression_new (GType value_type,
|
||||
/**
|
||||
* gtk_cclosure_expression_new:
|
||||
* @value_type: the type of the value that this expression evaluates to
|
||||
* @marshal: marshaller used for creating a closure
|
||||
* @marshal: (scope call): marshaller used for creating a closure
|
||||
* @n_params: the number of params needed for evaluating @closure
|
||||
* @params: (array length=n_params) (transfer full): expressions for each parameter
|
||||
* @callback_func: callback used for creating a closure
|
||||
* @callback_func: (scope notified) (closure user_data) (destroy user_destroy): callback used for creating a closure
|
||||
* @user_data: user data used for creating a closure
|
||||
* @user_destroy: destroy notify for @user_data
|
||||
*
|
||||
|
||||
@@ -101,6 +101,17 @@ gtk_functions_list_item_factory_init (GtkFunctionsListItemFactory *self)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_functions_list_item_factory_new: (skip)
|
||||
* @setup_func: (scope call) (destroy user_destroy): the setup function for the list item factory
|
||||
* @bind_func: (scope call) (destroy user_destroy): the bind function for the list item factory
|
||||
* @user_data: user data for the @setup_func and @bind_func functions
|
||||
* @user_destroy: a function called to destroy @user_data
|
||||
*
|
||||
* Creates a new #GtkListItemFactory with the given functions.
|
||||
*
|
||||
* Returns: (transfer full): the newly created list item factory object
|
||||
*/
|
||||
GtkListItemFactory *
|
||||
gtk_functions_list_item_factory_new (GtkListItemSetupFunc setup_func,
|
||||
GtkListItemBindFunc bind_func,
|
||||
|
||||
@@ -91,6 +91,8 @@ enum
|
||||
PROP_MIN_COLUMNS,
|
||||
PROP_MODEL,
|
||||
PROP_SINGLE_CLICK_ACTIVATE,
|
||||
PROP_ENABLE_RUBBERBAND,
|
||||
PROP_SEARCH_FILTER,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
@@ -914,6 +916,14 @@ gtk_grid_view_get_property (GObject *object,
|
||||
g_value_set_boolean (value, gtk_list_item_manager_get_single_click_activate (self->item_manager));
|
||||
break;
|
||||
|
||||
case PROP_ENABLE_RUBBERBAND:
|
||||
g_value_set_boolean (value, gtk_list_base_get_enable_rubberband (GTK_LIST_BASE (self)));
|
||||
break;
|
||||
|
||||
case PROP_SEARCH_FILTER:
|
||||
g_value_set_object (value, gtk_grid_view_get_search_filter (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -950,6 +960,14 @@ gtk_grid_view_set_property (GObject *object,
|
||||
gtk_grid_view_set_single_click_activate (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_ENABLE_RUBBERBAND:
|
||||
gtk_grid_view_set_enable_rubberband (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_SEARCH_FILTER:
|
||||
gtk_grid_view_set_search_filter (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -1062,6 +1080,30 @@ gtk_grid_view_class_init (GtkGridViewClass *klass)
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkGridView:enable-rubberband:
|
||||
*
|
||||
* Allow rubberband selection
|
||||
*/
|
||||
properties[PROP_ENABLE_RUBBERBAND] =
|
||||
g_param_spec_boolean ("enable-rubberband",
|
||||
P_("Enable rubberband selection"),
|
||||
P_("Allow selecting items by dragging with the mouse"),
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkGridView:search-filter:
|
||||
*
|
||||
* Filter used for search
|
||||
*/
|
||||
properties[PROP_SEARCH_FILTER] =
|
||||
g_param_spec_object ("search-filter",
|
||||
P_("Search filter"),
|
||||
P_("Filter used for searching"),
|
||||
GTK_TYPE_FILTER,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
|
||||
/**
|
||||
@@ -1370,3 +1412,102 @@ gtk_grid_view_get_single_click_activate (GtkGridView *self)
|
||||
|
||||
return gtk_list_item_manager_get_single_click_activate (self->item_manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_grid_view_set_enable_rubberband:
|
||||
* @self: a #GtkGridView
|
||||
* @enable_rubberband: %TRUE to enable rubberband selection
|
||||
*
|
||||
* Sets whether selections can be changed by dragging with the mouse.
|
||||
*/
|
||||
void
|
||||
gtk_grid_view_set_enable_rubberband (GtkGridView *self,
|
||||
gboolean enable_rubberband)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_GRID_VIEW (self));
|
||||
|
||||
if (enable_rubberband == gtk_list_base_get_enable_rubberband (GTK_LIST_BASE (self)))
|
||||
return;
|
||||
|
||||
gtk_list_base_set_enable_rubberband (GTK_LIST_BASE (self), enable_rubberband);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ENABLE_RUBBERBAND]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_grid_view_get_enable_rubberband:
|
||||
* @self: a #GtkGridView
|
||||
*
|
||||
* Returns whether rows can be selected by dragging with the mouse.
|
||||
*
|
||||
* Returns: %TRUE if rubberband selection is enabled
|
||||
*/
|
||||
gboolean
|
||||
gtk_grid_view_get_enable_rubberband (GtkGridView *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_GRID_VIEW (self), FALSE);
|
||||
|
||||
return gtk_list_base_get_enable_rubberband (GTK_LIST_BASE (self));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_grid_view_set_search_filter:
|
||||
* @self: a #GtkGridView
|
||||
* @filter: (nullable): the filter to use for search, or %NULL
|
||||
*
|
||||
* Sets a search filter.
|
||||
*
|
||||
* The selection will be moved to first item matching the
|
||||
* filter whenever the filter changes.
|
||||
*
|
||||
* This can be used with single selection and a string
|
||||
* filter that is connected to a search entry.
|
||||
*/
|
||||
void
|
||||
gtk_grid_view_set_search_filter (GtkGridView *self,
|
||||
GtkFilter *filter)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_GRID_VIEW (self));
|
||||
g_return_if_fail (filter == NULL || GTK_IS_FILTER (filter));
|
||||
|
||||
if (filter == gtk_list_base_get_search_filter (GTK_LIST_BASE (self)))
|
||||
return;
|
||||
|
||||
gtk_list_base_set_search_filter (GTK_LIST_BASE (self), filter);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SEARCH_FILTER]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_grid_view_get_search_filter:
|
||||
* @self: a #GtkGridView
|
||||
*
|
||||
* Gets the search filter that was set with
|
||||
* gtk_grid_view_set_search_filter().
|
||||
*
|
||||
* Returns: (transfer none): The search filter of @self
|
||||
*/
|
||||
GtkFilter *
|
||||
gtk_grid_view_get_search_filter (GtkGridView *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_GRID_VIEW (self), NULL);
|
||||
|
||||
return gtk_list_base_get_search_filter (GTK_LIST_BASE (self));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_grid_view_select_next_match:
|
||||
* @self: a #GtkGridView
|
||||
* @forward: whether to move forward or back
|
||||
*
|
||||
* Moves the selection to the next item matching the
|
||||
* search filter set with gtk_grid_view_set_search_filter().
|
||||
*/
|
||||
void
|
||||
gtk_grid_view_select_next_match (GtkGridView *self,
|
||||
gboolean forward)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_GRID_VIEW (self));
|
||||
|
||||
gtk_list_base_select_next_match (GTK_LIST_BASE (self), forward);
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#endif
|
||||
|
||||
#include <gtk/gtklistbase.h>
|
||||
#include <gtk/gtkfilter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -73,6 +74,11 @@ guint gtk_grid_view_get_max_columns (GtkGridView
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_grid_view_set_max_columns (GtkGridView *self,
|
||||
guint max_columns);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_grid_view_set_enable_rubberband (GtkGridView *self,
|
||||
gboolean enable_rubberband);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_grid_view_get_enable_rubberband (GtkGridView *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_grid_view_set_single_click_activate (GtkGridView *self,
|
||||
@@ -80,6 +86,16 @@ void gtk_grid_view_set_single_click_activate (GtkGridView
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_grid_view_get_single_click_activate (GtkGridView *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_grid_view_set_search_filter (GtkGridView *self,
|
||||
GtkFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilter * gtk_grid_view_get_search_filter (GtkGridView *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_grid_view_select_next_match (GtkGridView *self,
|
||||
gboolean forward);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -55,11 +55,6 @@
|
||||
#include "gdk/gdktextureprivate.h"
|
||||
#include "gdk/gdkprofilerprivate.h"
|
||||
|
||||
/* this is in case round() is not provided by the compiler,
|
||||
* such as in the case of C89 compilers, like MSVC
|
||||
*/
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtkicontheme
|
||||
* @Short_description: Looking up icons by name
|
||||
|
||||
@@ -18,10 +18,9 @@
|
||||
#include "config.h"
|
||||
#include "gtkkineticscrollingprivate.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/*
|
||||
* All our curves are second degree linear differential equations, and
|
||||
* so they can always be written as linear combinations of 2 base
|
||||
|
||||
+1
-6
@@ -63,11 +63,6 @@
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
/* this is in case rint() is not provided by the compiler,
|
||||
* such as in the case of C89 compilers, like MSVC
|
||||
*/
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtklabel
|
||||
* @Short_description: A widget that displays a small to medium amount of text
|
||||
@@ -2238,7 +2233,7 @@ extract_mnemonic_keyval (const char *text,
|
||||
p = g_utf8_next_char (p);
|
||||
c = g_utf8_get_char (p);
|
||||
|
||||
if (c != '_' && c != '0')
|
||||
if (c != '_' && c != '\0')
|
||||
{
|
||||
const gsize byte_index = p - text - 1; /* Of the _ */
|
||||
|
||||
|
||||
@@ -140,8 +140,6 @@
|
||||
|
||||
#include "a11y/gtklevelbaraccessible.h"
|
||||
|
||||
#include "fallback-c89.c"
|
||||
|
||||
enum {
|
||||
PROP_VALUE = 1,
|
||||
PROP_MIN_VALUE,
|
||||
|
||||
+605
-20
@@ -28,6 +28,12 @@
|
||||
#include "gtkscrollable.h"
|
||||
#include "gtksingleselection.h"
|
||||
#include "gtktypebuiltins.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkcssnodeprivate.h"
|
||||
#include "gtkstylecontextprivate.h"
|
||||
#include "gtksnapshot.h"
|
||||
#include "gtkmultiselection.h"
|
||||
|
||||
typedef struct _GtkListBasePrivate GtkListBasePrivate;
|
||||
|
||||
@@ -50,6 +56,24 @@ struct _GtkListBasePrivate
|
||||
GtkListItemTracker *selected;
|
||||
/* the item that has input focus */
|
||||
GtkListItemTracker *focus;
|
||||
|
||||
gboolean enable_rubberband;
|
||||
gboolean doing_rubberband;
|
||||
double rb_x1;
|
||||
double rb_y1;
|
||||
double rb_x2;
|
||||
double rb_y2;
|
||||
GtkGesture *drag_gesture;
|
||||
GtkCssNode *rubberband_node;
|
||||
GtkSelectionModel *old_selection;
|
||||
gboolean modify;
|
||||
gboolean extend;
|
||||
|
||||
guint autoscroll_id;
|
||||
double autoscroll_delta_x;
|
||||
double autoscroll_delta_y;
|
||||
|
||||
GtkFilter *search_filter;
|
||||
};
|
||||
|
||||
enum
|
||||
@@ -523,6 +547,8 @@ gtk_list_base_focus (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
static void gtk_list_base_clear_search_filter (GtkListBase *self);
|
||||
|
||||
static void
|
||||
gtk_list_base_dispose (GObject *object)
|
||||
{
|
||||
@@ -551,6 +577,8 @@ gtk_list_base_dispose (GObject *object)
|
||||
|
||||
g_clear_object (&priv->model);
|
||||
|
||||
gtk_list_base_clear_search_filter (self);
|
||||
|
||||
G_OBJECT_CLASS (gtk_list_base_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
@@ -764,26 +792,18 @@ gtk_list_base_update_focus_tracker (GtkListBase *self)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_scroll_to_item (GtkWidget *widget,
|
||||
const char *action_name,
|
||||
GVariant *parameter)
|
||||
static gboolean
|
||||
gtk_list_base_scroll_to_position (GtkListBase *self,
|
||||
guint pos)
|
||||
{
|
||||
GtkListBase *self = GTK_LIST_BASE (widget);
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
int start, end;
|
||||
double align_along, align_across;
|
||||
GtkPackType side_along, side_across;
|
||||
guint pos;
|
||||
|
||||
if (!g_variant_check_format_string (parameter, "u", FALSE))
|
||||
return;
|
||||
|
||||
g_variant_get (parameter, "u", &pos);
|
||||
|
||||
/* figure out primary orientation and if position is valid */
|
||||
if (!gtk_list_base_get_allocation_along (GTK_LIST_BASE (self), pos, &start, &end))
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
end += start;
|
||||
gtk_list_base_compute_scroll_align (self,
|
||||
@@ -794,7 +814,7 @@ gtk_list_base_scroll_to_item (GtkWidget *widget,
|
||||
|
||||
/* now do the same thing with the other orientation */
|
||||
if (!gtk_list_base_get_allocation_across (GTK_LIST_BASE (self), pos, &start, &end))
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
end += start;
|
||||
gtk_list_base_compute_scroll_align (self,
|
||||
@@ -808,13 +828,32 @@ gtk_list_base_scroll_to_item (GtkWidget *widget,
|
||||
align_across, side_across,
|
||||
align_along, side_along);
|
||||
|
||||
/* HACK HACK HACK
|
||||
*
|
||||
* GTK has no way to track the focused child. But we now that when a listitem
|
||||
* gets focus, it calls this action. So we update our focus tracker from here
|
||||
* because it's the closest we can get to accurate tracking.
|
||||
*/
|
||||
gtk_list_base_update_focus_tracker (self);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_scroll_to_item (GtkWidget *widget,
|
||||
const char *action_name,
|
||||
GVariant *parameter)
|
||||
{
|
||||
GtkListBase *self = GTK_LIST_BASE (widget);
|
||||
guint pos;
|
||||
|
||||
if (!g_variant_check_format_string (parameter, "u", FALSE))
|
||||
return;
|
||||
|
||||
g_variant_get (parameter, "u", &pos);
|
||||
|
||||
if (gtk_list_base_scroll_to_position (self, pos))
|
||||
{
|
||||
/* HACK HACK HACK
|
||||
*
|
||||
* GTK has no way to track the focused child. But we know that when a listitem
|
||||
* gets focus, it calls this action. So we update our focus tracker from here
|
||||
* because it's the closest we can get to accurate tracking.
|
||||
*/
|
||||
gtk_list_base_update_focus_tracker (self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -863,6 +902,17 @@ gtk_list_base_unselect_all (GtkWidget *widget,
|
||||
gtk_selection_model_unselect_all (selection_model);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_next_match_action (GtkWidget *widget,
|
||||
const char *action_name,
|
||||
GVariant *parameter)
|
||||
{
|
||||
gboolean forward;
|
||||
|
||||
g_variant_get (parameter, "(b)", &forward);
|
||||
gtk_list_base_select_next_match (GTK_LIST_BASE (widget), forward);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_base_move_cursor_to_start (GtkWidget *widget,
|
||||
GVariant *args,
|
||||
@@ -1061,6 +1111,20 @@ gtk_list_base_add_custom_move_binding (GtkWidgetClass *widget_class,
|
||||
"(bbb)", TRUE, TRUE, TRUE);
|
||||
}
|
||||
|
||||
static void gtk_list_base_snapshot_rubberband (GtkListBase *self,
|
||||
GtkSnapshot *snapshot);
|
||||
|
||||
static void
|
||||
gtk_list_base_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkListBase *self = GTK_LIST_BASE (widget);
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_list_base_parent_class)->snapshot (widget, snapshot);
|
||||
|
||||
gtk_list_base_snapshot_rubberband (self, snapshot);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_class_init (GtkListBaseClass *klass)
|
||||
{
|
||||
@@ -1069,6 +1133,7 @@ gtk_list_base_class_init (GtkListBaseClass *klass)
|
||||
gpointer iface;
|
||||
|
||||
widget_class->focus = gtk_list_base_focus;
|
||||
widget_class->snapshot = gtk_list_base_snapshot;
|
||||
|
||||
gobject_class->dispose = gtk_list_base_dispose;
|
||||
gobject_class->get_property = gtk_list_base_get_property;
|
||||
@@ -1162,6 +1227,11 @@ gtk_list_base_class_init (GtkListBaseClass *klass)
|
||||
NULL,
|
||||
gtk_list_base_unselect_all);
|
||||
|
||||
gtk_widget_class_install_action (widget_class,
|
||||
"list.next-match",
|
||||
"(b)",
|
||||
gtk_list_base_next_match_action);
|
||||
|
||||
gtk_list_base_add_move_binding (widget_class, GDK_KEY_Up, GTK_ORIENTATION_VERTICAL, -1);
|
||||
gtk_list_base_add_move_binding (widget_class, GDK_KEY_KP_Up, GTK_ORIENTATION_VERTICAL, -1);
|
||||
gtk_list_base_add_move_binding (widget_class, GDK_KEY_Down, GTK_ORIENTATION_VERTICAL, 1);
|
||||
@@ -1184,6 +1254,341 @@ gtk_list_base_class_init (GtkListBaseClass *klass)
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_slash, GDK_CONTROL_MASK, "list.select-all", NULL);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_A, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "list.unselect-all", NULL);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_backslash, GDK_CONTROL_MASK, "list.unselect-all", NULL);
|
||||
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_g, GDK_CONTROL_MASK, "list.next-match", "(b)", TRUE);
|
||||
gtk_widget_class_add_binding_action (widget_class, GDK_KEY_g, GDK_CONTROL_MASK | GDK_SHIFT_MASK, "list.next-match", "(b)", FALSE);
|
||||
}
|
||||
|
||||
static void gtk_list_base_update_rubberband_selection (GtkListBase *self);
|
||||
|
||||
static gboolean
|
||||
autoscroll_cb (GtkWidget *widget,
|
||||
GdkFrameClock *frame_clock,
|
||||
gpointer data)
|
||||
{
|
||||
GtkListBase *self = data;
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
double value;
|
||||
|
||||
value = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
|
||||
gtk_adjustment_set_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL], value + priv->autoscroll_delta_x);
|
||||
value = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
|
||||
gtk_adjustment_set_value (priv->adjustment[GTK_ORIENTATION_VERTICAL], value + priv->autoscroll_delta_y);
|
||||
|
||||
if (priv->doing_rubberband)
|
||||
{
|
||||
priv->rb_x2 += priv->autoscroll_delta_x;
|
||||
priv->rb_y2 += priv->autoscroll_delta_y;
|
||||
gtk_list_base_update_rubberband_selection (self);
|
||||
}
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
add_autoscroll (GtkListBase *self,
|
||||
double delta_x,
|
||||
double delta_y)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
|
||||
priv->autoscroll_delta_x = delta_x;
|
||||
priv->autoscroll_delta_y = delta_y;
|
||||
|
||||
if (priv->autoscroll_id == 0)
|
||||
priv->autoscroll_id = gtk_widget_add_tick_callback (GTK_WIDGET (self), autoscroll_cb, self, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_autoscroll (GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
|
||||
if (priv->autoscroll_id != 0)
|
||||
{
|
||||
gtk_widget_remove_tick_callback (GTK_WIDGET (self), priv->autoscroll_id);
|
||||
priv->autoscroll_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_start_rubberband (GtkListBase *self,
|
||||
double x,
|
||||
double y,
|
||||
gboolean modify,
|
||||
gboolean extend)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
GtkCssNode *widget_node;
|
||||
double value_x, value_y;
|
||||
GtkSelectionModel *selection;
|
||||
|
||||
if (priv->doing_rubberband)
|
||||
return;
|
||||
|
||||
value_x = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
|
||||
value_y = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
|
||||
|
||||
priv->rb_x1 = priv->rb_x2 = x + value_x;
|
||||
priv->rb_y1 = priv->rb_y2 = y + value_y;
|
||||
|
||||
priv->modify = modify;
|
||||
priv->extend = extend;
|
||||
|
||||
widget_node = gtk_widget_get_css_node (GTK_WIDGET (self));
|
||||
priv->rubberband_node = gtk_css_node_new ();
|
||||
gtk_css_node_set_name (priv->rubberband_node,
|
||||
g_quark_from_static_string ("rubberband"));
|
||||
gtk_css_node_set_parent (priv->rubberband_node, widget_node);
|
||||
gtk_css_node_set_state (priv->rubberband_node, gtk_css_node_get_state (widget_node));
|
||||
g_object_unref (priv->rubberband_node);
|
||||
|
||||
selection = gtk_list_item_manager_get_model (priv->item_manager);
|
||||
|
||||
if (modify)
|
||||
priv->old_selection = GTK_SELECTION_MODEL (gtk_multi_selection_copy (selection));
|
||||
|
||||
priv->doing_rubberband = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_stop_rubberband (GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
|
||||
if (!priv->doing_rubberband)
|
||||
return;
|
||||
|
||||
priv->doing_rubberband = FALSE;
|
||||
gtk_css_node_set_parent (priv->rubberband_node, NULL);
|
||||
priv->rubberband_node = NULL;
|
||||
|
||||
g_clear_object (&priv->old_selection);
|
||||
|
||||
remove_autoscroll (self);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
#define SCROLL_EDGE_SIZE 15
|
||||
|
||||
static void
|
||||
gtk_list_base_update_rubberband (GtkListBase *self,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
double value_x, value_y, page_size, upper;
|
||||
double delta_x, delta_y;
|
||||
|
||||
if (!priv->doing_rubberband)
|
||||
return;
|
||||
|
||||
value_x = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
|
||||
value_y = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
|
||||
|
||||
priv->rb_x2 = x + value_x;
|
||||
priv->rb_y2 = y + value_y;
|
||||
|
||||
gtk_list_base_update_rubberband_selection (self);
|
||||
|
||||
page_size = gtk_adjustment_get_page_size (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
|
||||
upper = gtk_adjustment_get_upper (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
|
||||
|
||||
if (x < SCROLL_EDGE_SIZE && value_x > 0)
|
||||
delta_x = - (SCROLL_EDGE_SIZE - x)/3.0;
|
||||
else if (page_size - x < SCROLL_EDGE_SIZE && value_x + page_size < upper)
|
||||
delta_x = (SCROLL_EDGE_SIZE - (page_size - x))/3.0;
|
||||
else
|
||||
delta_x = 0;
|
||||
|
||||
page_size = gtk_adjustment_get_page_size (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
|
||||
upper = gtk_adjustment_get_upper (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
|
||||
|
||||
if (y < SCROLL_EDGE_SIZE && value_y > 0)
|
||||
delta_y = - (SCROLL_EDGE_SIZE - y)/3.0;
|
||||
else if (page_size - y < SCROLL_EDGE_SIZE && value_y + page_size < upper)
|
||||
delta_y = (SCROLL_EDGE_SIZE - (page_size - y))/3.0;
|
||||
else
|
||||
delta_y = 0;
|
||||
|
||||
if (delta_x != 0 || delta_y != 0)
|
||||
add_autoscroll (self, delta_x, delta_y);
|
||||
else
|
||||
remove_autoscroll (self);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_update_rubberband_selection (GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
GdkRectangle rect;
|
||||
GdkRectangle alloc;
|
||||
double value_x, value_y;
|
||||
GtkSelectionModel *model;
|
||||
GtkListItemManagerItem *item;
|
||||
|
||||
value_x = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
|
||||
value_y = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
|
||||
|
||||
rect.x = MIN (priv->rb_x1, priv->rb_x2) - value_x;
|
||||
rect.y = MIN (priv->rb_y1, priv->rb_y2) - value_y;
|
||||
rect.width = ABS (priv->rb_x1 - priv->rb_x2) + 1;
|
||||
rect.height = ABS (priv->rb_y1 - priv->rb_y2) + 1;
|
||||
|
||||
model = gtk_list_item_manager_get_model (priv->item_manager);
|
||||
|
||||
for (item = gtk_list_item_manager_get_first (priv->item_manager);
|
||||
item != NULL;
|
||||
item = gtk_rb_tree_node_get_next (item))
|
||||
{
|
||||
guint pos;
|
||||
gboolean was_selected, selected;
|
||||
|
||||
if (!item->widget)
|
||||
continue;
|
||||
|
||||
pos = gtk_list_item_manager_get_item_position (priv->item_manager, item);
|
||||
|
||||
gtk_widget_get_allocation (item->widget, &alloc);
|
||||
|
||||
selected = gdk_rectangle_intersect (&rect, &alloc, &alloc);
|
||||
|
||||
if (priv->modify)
|
||||
{
|
||||
was_selected = gtk_selection_model_is_selected (priv->old_selection, pos);
|
||||
selected = selected ^ was_selected;
|
||||
}
|
||||
|
||||
if (selected)
|
||||
gtk_selection_model_select_item (model, pos, FALSE);
|
||||
else if (!priv->extend)
|
||||
gtk_selection_model_unselect_item (model, pos);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_snapshot_rubberband (GtkListBase *self,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
GtkStyleContext *context;
|
||||
GdkRectangle rect;
|
||||
double value_x, value_y;
|
||||
|
||||
if (!priv->doing_rubberband)
|
||||
return;
|
||||
|
||||
value_x = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_HORIZONTAL]);
|
||||
value_y = gtk_adjustment_get_value (priv->adjustment[GTK_ORIENTATION_VERTICAL]);
|
||||
|
||||
rect.x = MIN (priv->rb_x1, priv->rb_x2) - value_x;
|
||||
rect.y = MIN (priv->rb_y1, priv->rb_y2) - value_y;
|
||||
rect.width = ABS (priv->rb_x1 - priv->rb_x2) + 1;
|
||||
rect.height = ABS (priv->rb_y1 - priv->rb_y2) + 1;
|
||||
|
||||
context = gtk_widget_get_style_context (GTK_WIDGET (self));
|
||||
|
||||
gtk_style_context_save_to_node (context, priv->rubberband_node);
|
||||
|
||||
gtk_snapshot_render_background (snapshot, context, rect.x, rect.y, rect.width, rect.height);
|
||||
gtk_snapshot_render_frame (snapshot, context, rect.x, rect.y, rect.width, rect.height);
|
||||
|
||||
gtk_style_context_restore (context);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
get_selection_modifiers (GtkGesture *gesture,
|
||||
gboolean *modify,
|
||||
gboolean *extend)
|
||||
{
|
||||
GdkEventSequence *sequence;
|
||||
GdkEvent *event;
|
||||
GdkModifierType state;
|
||||
|
||||
*modify = FALSE;
|
||||
*extend = FALSE;
|
||||
|
||||
sequence = gtk_gesture_get_last_updated_sequence (gesture);
|
||||
event = gtk_gesture_get_last_event (gesture, sequence);
|
||||
state = gdk_event_get_modifier_state (event);
|
||||
if ((state & GDK_CONTROL_MASK) == GDK_CONTROL_MASK)
|
||||
*modify = TRUE;
|
||||
if ((state & GDK_SHIFT_MASK) == GDK_SHIFT_MASK)
|
||||
*extend = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_drag_begin (GtkGestureDrag *gesture,
|
||||
double start_x,
|
||||
double start_y,
|
||||
GtkListBase *self)
|
||||
{
|
||||
gboolean modify;
|
||||
gboolean extend;
|
||||
|
||||
get_selection_modifiers (GTK_GESTURE (gesture), &modify, &extend);
|
||||
gtk_list_base_start_rubberband (self, start_x, start_y, modify, extend);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_drag_update (GtkGestureDrag *gesture,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkListBase *self)
|
||||
{
|
||||
double start_x, start_y;
|
||||
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
|
||||
gtk_list_base_update_rubberband (self, start_x + offset_x, start_y + offset_y);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_drag_end (GtkGestureDrag *gesture,
|
||||
double offset_x,
|
||||
double offset_y,
|
||||
GtkListBase *self)
|
||||
{
|
||||
gtk_list_base_drag_update (gesture, offset_x, offset_y, self);
|
||||
gtk_list_base_stop_rubberband (self);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_list_base_set_enable_rubberband (GtkListBase *self,
|
||||
gboolean enable)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
|
||||
if (priv->enable_rubberband == enable)
|
||||
return;
|
||||
|
||||
priv->enable_rubberband = enable;
|
||||
|
||||
if (enable)
|
||||
{
|
||||
priv->drag_gesture = gtk_gesture_drag_new ();
|
||||
g_signal_connect (priv->drag_gesture, "drag-begin", G_CALLBACK (gtk_list_base_drag_begin), self);
|
||||
g_signal_connect (priv->drag_gesture, "drag-update", G_CALLBACK (gtk_list_base_drag_update), self);
|
||||
g_signal_connect (priv->drag_gesture, "drag-end", G_CALLBACK (gtk_list_base_drag_end), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (priv->drag_gesture));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_remove_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (priv->drag_gesture));
|
||||
priv->drag_gesture = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_list_base_get_enable_rubberband (GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
|
||||
return priv->enable_rubberband;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1538,3 +1943,183 @@ gtk_list_base_set_model (GtkListBase *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static guint
|
||||
find_first_selected (GtkSelectionModel *model)
|
||||
{
|
||||
guint i, start, n_items;
|
||||
gboolean selected;
|
||||
|
||||
n_items = 0;
|
||||
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (model)); i += n_items)
|
||||
{
|
||||
gtk_selection_model_query_range (model, i, &start, &n_items, &selected);
|
||||
if (selected)
|
||||
return i;
|
||||
}
|
||||
|
||||
return GTK_INVALID_LIST_POSITION;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
match_item (GListModel *model,
|
||||
GtkFilter *filter,
|
||||
guint position)
|
||||
{
|
||||
gpointer item;
|
||||
gboolean result;
|
||||
|
||||
item = g_list_model_get_item (model, position);
|
||||
result = gtk_filter_match (filter, item);
|
||||
g_object_unref (item);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static guint
|
||||
find_next_match (GListModel *model,
|
||||
GtkFilter *filter,
|
||||
guint start,
|
||||
gboolean forward)
|
||||
{
|
||||
guint i;
|
||||
|
||||
if (start == GTK_INVALID_LIST_POSITION)
|
||||
start = 0;
|
||||
|
||||
if (forward)
|
||||
for (i = start; i < g_list_model_get_n_items (model); i++)
|
||||
{
|
||||
if (match_item (model, filter, i))
|
||||
return i;
|
||||
}
|
||||
else
|
||||
for (i = start; ; i--)
|
||||
{
|
||||
if (match_item (model, filter, i))
|
||||
return i;
|
||||
if (i == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return GTK_INVALID_LIST_POSITION;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_search_filter_changed_cb (GtkFilter *filter,
|
||||
GtkFilterChange change,
|
||||
GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
GtkSelectionModel *model = gtk_list_item_manager_get_model (priv->item_manager);
|
||||
|
||||
if (model == NULL)
|
||||
return;
|
||||
|
||||
if (gtk_filter_get_strictness (priv->search_filter) == GTK_FILTER_MATCH_NONE)
|
||||
gtk_selection_model_unselect_all (model);
|
||||
else
|
||||
{
|
||||
guint position;
|
||||
|
||||
switch (change)
|
||||
{
|
||||
case GTK_FILTER_CHANGE_DIFFERENT:
|
||||
case GTK_FILTER_CHANGE_LESS_STRICT:
|
||||
position = find_next_match (G_LIST_MODEL (model), priv->search_filter, 0, TRUE);
|
||||
break;
|
||||
|
||||
case GTK_FILTER_CHANGE_MORE_STRICT:
|
||||
position = find_first_selected (model);
|
||||
if (position == GTK_INVALID_LIST_POSITION)
|
||||
position = 0;
|
||||
position = find_next_match (G_LIST_MODEL (model), priv->search_filter, position, TRUE);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
if (position == GTK_INVALID_LIST_POSITION)
|
||||
gtk_selection_model_unselect_all (model);
|
||||
else
|
||||
gtk_list_base_grab_focus_on_item (self, position, TRUE, FALSE, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_base_clear_search_filter (GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
|
||||
if (priv->search_filter == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (priv->search_filter,
|
||||
gtk_list_base_search_filter_changed_cb,
|
||||
self);
|
||||
|
||||
g_clear_object (&priv->search_filter);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_list_base_set_search_filter (GtkListBase *self,
|
||||
GtkFilter *filter)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
|
||||
if (priv->search_filter == filter)
|
||||
return;
|
||||
|
||||
gtk_list_base_clear_search_filter (self);
|
||||
|
||||
if (filter)
|
||||
{
|
||||
priv->search_filter = g_object_ref (filter);
|
||||
g_signal_connect (priv->search_filter, "changed",
|
||||
G_CALLBACK (gtk_list_base_search_filter_changed_cb), self);
|
||||
gtk_list_base_search_filter_changed_cb (priv->search_filter, GTK_FILTER_CHANGE_DIFFERENT, self);
|
||||
}
|
||||
|
||||
gtk_widget_action_set_enabled (GTK_WIDGET (self), "list.next-match", filter != NULL);
|
||||
}
|
||||
|
||||
GtkFilter *
|
||||
gtk_list_base_get_search_filter (GtkListBase *self)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
|
||||
return priv->search_filter;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_list_base_select_next_match (GtkListBase *self,
|
||||
gboolean forward)
|
||||
{
|
||||
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||
GtkSelectionModel *model = gtk_list_item_manager_get_model (priv->item_manager);
|
||||
guint position;
|
||||
|
||||
if (!priv->search_filter)
|
||||
return FALSE;
|
||||
|
||||
position = find_first_selected (model);
|
||||
if (position == GTK_INVALID_LIST_POSITION)
|
||||
return FALSE;
|
||||
|
||||
if (forward)
|
||||
position = position + 1;
|
||||
else if (position > 0)
|
||||
position = position - 1;
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
position = find_next_match (G_LIST_MODEL (model), priv->search_filter, position, forward);
|
||||
if (position == GTK_INVALID_LIST_POSITION)
|
||||
{
|
||||
gtk_widget_error_bell (GTK_WIDGET (self));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
gtk_list_base_grab_focus_on_item (self, position, TRUE, FALSE, FALSE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "gtklistbase.h"
|
||||
|
||||
#include "gtklistitemmanagerprivate.h"
|
||||
#include "gtkfilter.h"
|
||||
#include "gtkprivate.h"
|
||||
|
||||
struct _GtkListBase
|
||||
@@ -99,5 +100,13 @@ gboolean gtk_list_base_grab_focus_on_item (GtkListBase
|
||||
gboolean select,
|
||||
gboolean modify,
|
||||
gboolean extend);
|
||||
void gtk_list_base_set_enable_rubberband (GtkListBase *self,
|
||||
gboolean enable);
|
||||
gboolean gtk_list_base_get_enable_rubberband (GtkListBase *self);
|
||||
void gtk_list_base_set_search_filter (GtkListBase *self,
|
||||
GtkFilter *filter);
|
||||
GtkFilter * gtk_list_base_get_search_filter (GtkListBase *self);
|
||||
gboolean gtk_list_base_select_next_match (GtkListBase *self,
|
||||
gboolean forward);
|
||||
|
||||
#endif /* __GTK_LIST_BASE_PRIVATE_H__ */
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "gtkintl.h"
|
||||
#include "gtklistitemfactoryprivate.h"
|
||||
#include "gtklistitemprivate.h"
|
||||
#include "gtklistbaseprivate.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkselectionmodel.h"
|
||||
#include "gtkwidget.h"
|
||||
@@ -309,6 +310,8 @@ gtk_list_item_widget_click_gesture_pressed (GtkGestureClick *gesture,
|
||||
{
|
||||
GtkListItemWidgetPrivate *priv = gtk_list_item_widget_get_instance_private (self);
|
||||
GtkWidget *widget = GTK_WIDGET (self);
|
||||
GtkWidget * parent = gtk_widget_get_parent (widget);
|
||||
gboolean rubberband;
|
||||
|
||||
if (priv->list_item && !priv->list_item->selectable && !priv->list_item->activatable)
|
||||
{
|
||||
@@ -316,7 +319,12 @@ gtk_list_item_widget_click_gesture_pressed (GtkGestureClick *gesture,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!priv->list_item || priv->list_item->selectable)
|
||||
if (GTK_IS_LIST_BASE (parent))
|
||||
rubberband = gtk_list_base_get_enable_rubberband (GTK_LIST_BASE (parent));
|
||||
else
|
||||
rubberband = FALSE;
|
||||
|
||||
if (!rubberband && (!priv->list_item || priv->list_item->selectable))
|
||||
{
|
||||
GdkModifierType state;
|
||||
GdkEvent *event;
|
||||
|
||||
@@ -85,6 +85,8 @@ enum
|
||||
PROP_MODEL,
|
||||
PROP_SHOW_SEPARATORS,
|
||||
PROP_SINGLE_CLICK_ACTIVATE,
|
||||
PROP_ENABLE_RUBBERBAND,
|
||||
PROP_SEARCH_FILTER,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
@@ -643,6 +645,14 @@ gtk_list_view_get_property (GObject *object,
|
||||
g_value_set_boolean (value, gtk_list_item_manager_get_single_click_activate (self->item_manager));
|
||||
break;
|
||||
|
||||
case PROP_ENABLE_RUBBERBAND:
|
||||
g_value_set_boolean (value, gtk_list_base_get_enable_rubberband (GTK_LIST_BASE (self)));
|
||||
break;
|
||||
|
||||
case PROP_SEARCH_FILTER:
|
||||
g_value_set_object (value, gtk_list_view_get_search_filter (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -675,6 +685,14 @@ gtk_list_view_set_property (GObject *object,
|
||||
gtk_list_view_set_single_click_activate (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_ENABLE_RUBBERBAND:
|
||||
gtk_list_view_set_enable_rubberband (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_SEARCH_FILTER:
|
||||
gtk_list_view_set_search_filter (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -771,6 +789,30 @@ gtk_list_view_class_init (GtkListViewClass *klass)
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkListView:enable-rubberband:
|
||||
*
|
||||
* Allow rubberband selection
|
||||
*/
|
||||
properties[PROP_ENABLE_RUBBERBAND] =
|
||||
g_param_spec_boolean ("enable-rubberband",
|
||||
P_("Enable rubberband selection"),
|
||||
P_("Allow selecting items by dragging with the mouse"),
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkListView:search-filter:
|
||||
*
|
||||
* Filter used for search
|
||||
*/
|
||||
properties[PROP_SEARCH_FILTER] =
|
||||
g_param_spec_object ("search-filter",
|
||||
P_("Search filter"),
|
||||
P_("Filter used for searching"),
|
||||
GTK_TYPE_FILTER,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
|
||||
/**
|
||||
@@ -1033,3 +1075,103 @@ gtk_list_view_get_single_click_activate (GtkListView *self)
|
||||
|
||||
return gtk_list_item_manager_get_single_click_activate (self->item_manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_list_view_set_enable_rubberband:
|
||||
* @self: a #GtkListView
|
||||
* @enable_rubberband: %TRUE to enable rubberband selection
|
||||
*
|
||||
* Sets whether selections can be changed by dragging with the mouse.
|
||||
*/
|
||||
void
|
||||
gtk_list_view_set_enable_rubberband (GtkListView *self,
|
||||
gboolean enable_rubberband)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_LIST_VIEW (self));
|
||||
|
||||
if (enable_rubberband == gtk_list_base_get_enable_rubberband (GTK_LIST_BASE (self)))
|
||||
return;
|
||||
|
||||
gtk_list_base_set_enable_rubberband (GTK_LIST_BASE (self), enable_rubberband);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ENABLE_RUBBERBAND]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_list_view_get_enable_rubberband:
|
||||
* @self: a #GtkListView
|
||||
*
|
||||
* Returns whether rows can be selected by dragging with the mouse.
|
||||
*
|
||||
* Returns: %TRUE if rubberband selection is enabled
|
||||
*/
|
||||
gboolean
|
||||
gtk_list_view_get_enable_rubberband (GtkListView *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_LIST_VIEW (self), FALSE);
|
||||
|
||||
return gtk_list_base_get_enable_rubberband (GTK_LIST_BASE (self));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_list_view_set_search_filter:
|
||||
* @self: a #GtkListView
|
||||
* @filter: (nullable): the filter ot use for search, or %NULL
|
||||
*
|
||||
* Sets a search filter.
|
||||
*
|
||||
* The selection will be moved to first item matching the
|
||||
* filter whenever the filter changes.
|
||||
*
|
||||
* This can be used with single selection and a string
|
||||
* filter that is connected to a search entry.
|
||||
*/
|
||||
void
|
||||
gtk_list_view_set_search_filter (GtkListView *self,
|
||||
GtkFilter *filter)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_LIST_VIEW (self));
|
||||
g_return_if_fail (filter == NULL || GTK_IS_FILTER (filter));
|
||||
|
||||
if (filter == gtk_list_base_get_search_filter (GTK_LIST_BASE (self)))
|
||||
return;
|
||||
|
||||
gtk_list_base_set_search_filter (GTK_LIST_BASE (self), filter);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SEARCH_FILTER]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_list_view_get_search_filter:
|
||||
* @self: a #GtkListView
|
||||
*
|
||||
* Gets the search filter that was set with
|
||||
* gtk_list_view_set_search_filter().
|
||||
*
|
||||
* Returns: (transfer none): The search filter of @self
|
||||
*/
|
||||
GtkFilter *
|
||||
gtk_list_view_get_search_filter (GtkListView *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_LIST_VIEW (self), NULL);
|
||||
|
||||
return gtk_list_base_get_search_filter (GTK_LIST_BASE (self));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_list_view_select_next_match:
|
||||
* @self: a #GtkListView
|
||||
* @forward: whether to move forward or back
|
||||
*
|
||||
* Moves the selection to the next item matching the
|
||||
* search filter set with gtk_list_view_set_search_filter().
|
||||
*/
|
||||
void
|
||||
gtk_list_view_select_next_match (GtkListView *self,
|
||||
gboolean forward)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_LIST_VIEW (self));
|
||||
|
||||
gtk_list_base_select_next_match (GTK_LIST_BASE (self), forward);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#endif
|
||||
|
||||
#include <gtk/gtklistbase.h>
|
||||
#include <gtk/gtkfilter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@@ -75,6 +76,22 @@ void gtk_list_view_set_single_click_activate (GtkListView
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_list_view_get_single_click_activate (GtkListView *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_list_view_set_enable_rubberband (GtkListView *self,
|
||||
gboolean enable_rubberband);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_list_view_get_enable_rubberband (GtkListView *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_list_view_set_search_filter (GtkListView *self,
|
||||
GtkFilter *filter);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkFilter * gtk_list_view_get_search_filter (GtkListView *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_list_view_select_next_match (GtkListView *self,
|
||||
gboolean forward);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_LIST_VIEW_H__ */
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* Copyright © 2019 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 <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkmultiselection.h"
|
||||
|
||||
#include "gtkintl.h"
|
||||
#include "gtkselectionmodel.h"
|
||||
#include "gtksingleselection.h"
|
||||
#include "gtkset.h"
|
||||
|
||||
/**
|
||||
* SECTION:gtkmultiselection
|
||||
* @Short_description: A selection model that allows selecting a multiple items
|
||||
* @Title: GtkMultiSelection
|
||||
* @see_also: #GtkSelectionModel
|
||||
*
|
||||
* GtkMultiSelection is an implementation of the #GtkSelectionModel interface
|
||||
* that allows selecting multiple elements.
|
||||
*/
|
||||
|
||||
struct _GtkMultiSelection
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
GListModel *model;
|
||||
|
||||
GtkSet *selected;
|
||||
guint last_selected;
|
||||
};
|
||||
|
||||
struct _GtkMultiSelectionClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_MODEL,
|
||||
|
||||
N_PROPS,
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS] = { NULL, };
|
||||
|
||||
static GType
|
||||
gtk_multi_selection_get_item_type (GListModel *list)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (list);
|
||||
|
||||
return g_list_model_get_item_type (self->model);
|
||||
}
|
||||
|
||||
static guint
|
||||
gtk_multi_selection_get_n_items (GListModel *list)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (list);
|
||||
|
||||
return g_list_model_get_n_items (self->model);
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gtk_multi_selection_get_item (GListModel *list,
|
||||
guint position)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (list);
|
||||
|
||||
return g_list_model_get_item (self->model, position);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_multi_selection_list_model_init (GListModelInterface *iface)
|
||||
{
|
||||
iface->get_item_type = gtk_multi_selection_get_item_type;
|
||||
iface->get_n_items = gtk_multi_selection_get_n_items;
|
||||
iface->get_item = gtk_multi_selection_get_item;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_is_selected (GtkSelectionModel *model,
|
||||
guint position)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
|
||||
return gtk_set_contains (self->selected, position);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_select_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items,
|
||||
gboolean exclusive)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
|
||||
if (exclusive)
|
||||
gtk_set_remove_all (self->selected);
|
||||
gtk_set_add_range (self->selected, position, n_items);
|
||||
gtk_selection_model_selection_changed (model, position, n_items);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_unselect_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint n_items)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
|
||||
gtk_set_remove_range (self->selected, position, n_items);
|
||||
gtk_selection_model_selection_changed (model, position, n_items);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_select_item (GtkSelectionModel *model,
|
||||
guint position,
|
||||
gboolean exclusive)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
guint pos, n_items;
|
||||
|
||||
pos = position;
|
||||
n_items = 1;
|
||||
|
||||
self->last_selected = position;
|
||||
return gtk_multi_selection_select_range (model, pos, n_items, exclusive);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_unselect_item (GtkSelectionModel *model,
|
||||
guint position)
|
||||
{
|
||||
return gtk_multi_selection_unselect_range (model, position, 1);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_select_all (GtkSelectionModel *model)
|
||||
{
|
||||
return gtk_multi_selection_select_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)), FALSE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_multi_selection_unselect_all (GtkSelectionModel *model)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
self->last_selected = GTK_INVALID_LIST_POSITION;
|
||||
return gtk_multi_selection_unselect_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model)));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_multi_selection_query_range (GtkSelectionModel *model,
|
||||
guint position,
|
||||
guint *start_range,
|
||||
guint *n_items,
|
||||
gboolean *selected)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (model);
|
||||
guint upper_bound = g_list_model_get_n_items (self->model);
|
||||
|
||||
gtk_set_find_range (self->selected, position, upper_bound, start_range, n_items, selected);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_multi_selection_selection_model_init (GtkSelectionModelInterface *iface)
|
||||
{
|
||||
iface->is_selected = gtk_multi_selection_is_selected;
|
||||
iface->select_item = gtk_multi_selection_select_item;
|
||||
iface->unselect_item = gtk_multi_selection_unselect_item;
|
||||
iface->select_range = gtk_multi_selection_select_range;
|
||||
iface->unselect_range = gtk_multi_selection_unselect_range;
|
||||
iface->select_all = gtk_multi_selection_select_all;
|
||||
iface->unselect_all = gtk_multi_selection_unselect_all;
|
||||
iface->query_range = gtk_multi_selection_query_range;
|
||||
}
|
||||
|
||||
G_DEFINE_TYPE_EXTENDED (GtkMultiSelection, gtk_multi_selection, G_TYPE_OBJECT, 0,
|
||||
G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL,
|
||||
gtk_multi_selection_list_model_init)
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_SELECTION_MODEL,
|
||||
gtk_multi_selection_selection_model_init))
|
||||
|
||||
static void
|
||||
gtk_multi_selection_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GtkMultiSelection *self)
|
||||
{
|
||||
gtk_set_remove_range (self->selected, position, removed);
|
||||
gtk_set_shift (self->selected, position, (int)added - (int)removed);
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_multi_selection_clear_model (GtkMultiSelection *self)
|
||||
{
|
||||
if (self->model == NULL)
|
||||
return;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (self->model,
|
||||
gtk_multi_selection_items_changed_cb,
|
||||
self);
|
||||
g_clear_object (&self->model);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_multi_selection_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_MODEL:
|
||||
self->model = g_value_dup_object (value);
|
||||
g_warn_if_fail (self->model != NULL);
|
||||
g_signal_connect (self->model,
|
||||
"items-changed",
|
||||
G_CALLBACK (gtk_multi_selection_items_changed_cb),
|
||||
self);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_multi_selection_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
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_multi_selection_dispose (GObject *object)
|
||||
{
|
||||
GtkMultiSelection *self = GTK_MULTI_SELECTION (object);
|
||||
|
||||
gtk_multi_selection_clear_model (self);
|
||||
|
||||
g_clear_pointer (&self->selected, gtk_set_free);
|
||||
self->last_selected = GTK_INVALID_LIST_POSITION;
|
||||
|
||||
G_OBJECT_CLASS (gtk_multi_selection_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_multi_selection_class_init (GtkMultiSelectionClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = gtk_multi_selection_get_property;
|
||||
gobject_class->set_property = gtk_multi_selection_set_property;
|
||||
gobject_class->dispose = gtk_multi_selection_dispose;
|
||||
|
||||
/**
|
||||
* GtkMultiSelection:model
|
||||
*
|
||||
* The list managed by this selection
|
||||
*/
|
||||
properties[PROP_MODEL] =
|
||||
g_param_spec_object ("model",
|
||||
P_("Model"),
|
||||
P_("List managed by this selection"),
|
||||
G_TYPE_LIST_MODEL,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_multi_selection_init (GtkMultiSelection *self)
|
||||
{
|
||||
self->selected = gtk_set_new ();
|
||||
self->last_selected = GTK_INVALID_LIST_POSITION;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_multi_selection_new:
|
||||
* @model: (transfer none): the #GListModel to manage
|
||||
*
|
||||
* Creates a new selection to handle @model.
|
||||
*
|
||||
* Returns: (transfer full) (type GtkMultiSelection): a new #GtkMultiSelection
|
||||
**/
|
||||
GListModel *
|
||||
gtk_multi_selection_new (GListModel *model)
|
||||
{
|
||||
g_return_val_if_fail (G_IS_LIST_MODEL (model), NULL);
|
||||
|
||||
return g_object_new (GTK_TYPE_MULTI_SELECTION,
|
||||
"model", model,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_multi_selection_copy:
|
||||
* @selection: the #GtkSelectionModel to copy
|
||||
*
|
||||
* Creates a #GtkMultiSelection that has the same underlying
|
||||
* model and the same selected items as @selection.
|
||||
*
|
||||
* Returns: (transfer full): a new #GtkMultiSelection
|
||||
*/
|
||||
GtkMultiSelection *
|
||||
gtk_multi_selection_copy (GtkSelectionModel *selection)
|
||||
{
|
||||
GtkMultiSelection *copy;
|
||||
GListModel *model;
|
||||
|
||||
g_object_get (selection, "model", &model, NULL);
|
||||
|
||||
copy = GTK_MULTI_SELECTION (gtk_multi_selection_new (model));
|
||||
|
||||
if (GTK_IS_MULTI_SELECTION (selection))
|
||||
{
|
||||
GtkMultiSelection *multi = GTK_MULTI_SELECTION (selection);
|
||||
|
||||
gtk_set_free (copy->selected);
|
||||
copy->selected = gtk_set_copy (multi->selected);
|
||||
copy->last_selected = multi->last_selected;
|
||||
}
|
||||
else
|
||||
{
|
||||
guint pos, n;
|
||||
guint start, n_items;
|
||||
gboolean selected;
|
||||
|
||||
n = g_list_model_get_n_items (model);
|
||||
n_items = 0;
|
||||
for (pos = 0; pos < n; pos += n_items)
|
||||
{
|
||||
gtk_selection_model_query_range (selection, pos, &start, &n_items, &selected);
|
||||
if (selected)
|
||||
gtk_selection_model_select_range (GTK_SELECTION_MODEL (copy), start, n_items, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (model);
|
||||
|
||||
return copy;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright © 2019 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 <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_MULTI_SELECTION_H__
|
||||
#define __GTK_MULTI_SELECTION_H__
|
||||
|
||||
#include <gtk/gtktypes.h>
|
||||
#include <gtk/gtkselectionmodel.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_MULTI_SELECTION (gtk_multi_selection_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
G_DECLARE_FINAL_TYPE (GtkMultiSelection, gtk_multi_selection, GTK, MULTI_SELECTION, GObject)
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel * gtk_multi_selection_new (GListModel *model);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkMultiSelection * gtk_multi_selection_copy (GtkSelectionModel *selection);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_MULTI_SELECTION_H__ */
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "gtktypebuiltins.h"
|
||||
|
||||
#include <math.h>
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtknumericsorter
|
||||
@@ -127,11 +126,11 @@ gtk_numeric_sorter_compare (GtkSorter *sorter,
|
||||
float num1 = g_value_get_float (&value1);
|
||||
float num2 = g_value_get_float (&value2);
|
||||
|
||||
if (isnanf (num1) && isnanf (num2))
|
||||
if (isnan (num1) && isnan (num2))
|
||||
result = GTK_ORDERING_EQUAL;
|
||||
else if (isnanf (num1))
|
||||
else if (isnan (num1))
|
||||
result = self->sort_order == GTK_SORT_ASCENDING ? GTK_ORDERING_LARGER : GTK_ORDERING_SMALLER;
|
||||
else if (isnanf (num2))
|
||||
else if (isnan (num2))
|
||||
result = self->sort_order == GTK_SORT_ASCENDING ? GTK_ORDERING_SMALLER : GTK_ORDERING_LARGER;
|
||||
else if (num1 < num2)
|
||||
result = self->sort_order == GTK_SORT_ASCENDING ? GTK_ORDERING_SMALLER : GTK_ORDERING_LARGER;
|
||||
|
||||
+59
-73
@@ -29,6 +29,7 @@
|
||||
#include "gtkprintbackendprivate.h"
|
||||
|
||||
|
||||
static void gtk_print_backend_finalize (GObject *object);
|
||||
static void gtk_print_backend_dispose (GObject *object);
|
||||
static void gtk_print_backend_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
@@ -41,7 +42,7 @@ static void gtk_print_backend_get_property (GObject *object,
|
||||
|
||||
struct _GtkPrintBackendPrivate
|
||||
{
|
||||
GHashTable *printers;
|
||||
GListStore *printers;
|
||||
guint printer_list_requested : 1;
|
||||
guint printer_list_done : 1;
|
||||
GtkPrintBackendStatus status;
|
||||
@@ -251,6 +252,7 @@ gtk_print_backend_class_init (GtkPrintBackendClass *class)
|
||||
|
||||
backend_parent_class = g_type_class_peek_parent (class);
|
||||
|
||||
object_class->finalize = gtk_print_backend_finalize;
|
||||
object_class->dispose = gtk_print_backend_dispose;
|
||||
object_class->set_property = gtk_print_backend_set_property;
|
||||
object_class->get_property = gtk_print_backend_get_property;
|
||||
@@ -331,9 +333,7 @@ gtk_print_backend_init (GtkPrintBackend *backend)
|
||||
|
||||
priv = backend->priv = gtk_print_backend_get_instance_private (backend);
|
||||
|
||||
priv->printers = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
(GDestroyNotify) g_free,
|
||||
(GDestroyNotify) g_object_unref);
|
||||
priv->printers = g_list_store_new (GTK_TYPE_PRINTER);
|
||||
priv->auth_info_required = NULL;
|
||||
priv->auth_info = NULL;
|
||||
}
|
||||
@@ -350,15 +350,21 @@ gtk_print_backend_dispose (GObject *object)
|
||||
/* We unref the printers in dispose, not in finalize so that
|
||||
* we can break refcount cycles with gtk_print_backend_destroy
|
||||
*/
|
||||
if (priv->printers)
|
||||
{
|
||||
g_hash_table_destroy (priv->printers);
|
||||
priv->printers = NULL;
|
||||
}
|
||||
g_list_store_remove_all (priv->printers);
|
||||
|
||||
backend_parent_class->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_print_backend_finalize (GObject *object)
|
||||
{
|
||||
GtkPrintBackend *backend = GTK_PRINT_BACKEND (object);
|
||||
GtkPrintBackendPrivate *priv = backend->priv;
|
||||
|
||||
g_clear_object (&priv->printers);
|
||||
|
||||
backend_parent_class->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fallback_printer_request_details (GtkPrinter *printer)
|
||||
@@ -367,7 +373,7 @@ fallback_printer_request_details (GtkPrinter *printer)
|
||||
|
||||
static gboolean
|
||||
fallback_printer_mark_conflicts (GtkPrinter *printer,
|
||||
GtkPrinterOptionSet *options)
|
||||
GtkPrinterOptionSet *options)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
@@ -411,58 +417,25 @@ fallback_printer_get_capabilities (GtkPrinter *printer)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
printer_hash_to_sorted_active_list (const gchar *key,
|
||||
gpointer value,
|
||||
GList **out_list)
|
||||
{
|
||||
GtkPrinter *printer;
|
||||
|
||||
printer = GTK_PRINTER (value);
|
||||
|
||||
if (gtk_printer_get_name (printer) == NULL)
|
||||
return;
|
||||
|
||||
if (!gtk_printer_is_active (printer))
|
||||
return;
|
||||
|
||||
*out_list = g_list_insert_sorted (*out_list, value, (GCompareFunc) gtk_printer_compare);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gtk_print_backend_add_printer (GtkPrintBackend *backend,
|
||||
GtkPrinter *printer)
|
||||
{
|
||||
GtkPrintBackendPrivate *priv;
|
||||
|
||||
g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
|
||||
|
||||
priv = backend->priv;
|
||||
|
||||
if (!priv->printers)
|
||||
return;
|
||||
|
||||
g_hash_table_insert (priv->printers,
|
||||
g_strdup (gtk_printer_get_name (printer)),
|
||||
g_object_ref (printer));
|
||||
g_list_store_append (backend->priv->printers, printer);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_print_backend_remove_printer (GtkPrintBackend *backend,
|
||||
GtkPrinter *printer)
|
||||
{
|
||||
GtkPrintBackendPrivate *priv;
|
||||
guint position;
|
||||
|
||||
g_return_if_fail (GTK_IS_PRINT_BACKEND (backend));
|
||||
priv = backend->priv;
|
||||
|
||||
if (!priv->printers)
|
||||
return;
|
||||
|
||||
g_hash_table_remove (priv->printers,
|
||||
gtk_printer_get_name (printer));
|
||||
if (g_list_store_find (backend->priv->printers, printer, &position))
|
||||
g_list_store_remove (backend->priv->printers, position);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -488,54 +461,67 @@ gtk_print_backend_set_list_done (GtkPrintBackend *backend)
|
||||
GList *
|
||||
gtk_print_backend_get_printer_list (GtkPrintBackend *backend)
|
||||
{
|
||||
GtkPrintBackendPrivate *priv;
|
||||
GList *result;
|
||||
GList *result = NULL;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
|
||||
|
||||
priv = backend->priv;
|
||||
for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (backend->priv->printers)); i++)
|
||||
{
|
||||
GtkPrinter *printer = g_list_model_get_item (G_LIST_MODEL (backend->priv->printers), i);
|
||||
result = g_list_prepend (result, printer);
|
||||
g_object_unref (printer);
|
||||
}
|
||||
|
||||
result = NULL;
|
||||
if (priv->printers != NULL)
|
||||
g_hash_table_foreach (priv->printers,
|
||||
(GHFunc) printer_hash_to_sorted_active_list,
|
||||
&result);
|
||||
|
||||
if (!priv->printer_list_requested && priv->printers != NULL)
|
||||
if (!backend->priv->printer_list_requested)
|
||||
{
|
||||
if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list)
|
||||
GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
|
||||
priv->printer_list_requested = TRUE;
|
||||
backend->priv->printer_list_requested = TRUE;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend)
|
||||
GListModel *
|
||||
gtk_print_backend_get_printers (GtkPrintBackend *backend)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_PRINT_BACKEND (print_backend), TRUE);
|
||||
if (!backend->priv->printer_list_requested)
|
||||
{
|
||||
if (GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list)
|
||||
GTK_PRINT_BACKEND_GET_CLASS (backend)->request_printer_list (backend);
|
||||
backend->priv->printer_list_requested = TRUE;
|
||||
}
|
||||
|
||||
return print_backend->priv->printer_list_done;
|
||||
return G_LIST_MODEL (backend->priv->printers);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_print_backend_printer_list_is_done (GtkPrintBackend *backend)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), TRUE);
|
||||
|
||||
return backend->priv->printer_list_done;
|
||||
}
|
||||
|
||||
GtkPrinter *
|
||||
gtk_print_backend_find_printer (GtkPrintBackend *backend,
|
||||
const gchar *printer_name)
|
||||
{
|
||||
GtkPrintBackendPrivate *priv;
|
||||
GtkPrinter *printer;
|
||||
GtkPrinter *result = NULL;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_PRINT_BACKEND (backend), NULL);
|
||||
|
||||
priv = backend->priv;
|
||||
for (i = 0; !result && i < g_list_model_get_n_items (G_LIST_MODEL (backend->priv->printers)); i++)
|
||||
{
|
||||
GtkPrinter *printer = g_list_model_get_item (G_LIST_MODEL (backend->priv->printers), i);
|
||||
if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
|
||||
result = printer;
|
||||
g_object_unref (printer);
|
||||
}
|
||||
|
||||
if (priv->printers)
|
||||
printer = g_hash_table_lookup (priv->printers, printer_name);
|
||||
else
|
||||
printer = NULL;
|
||||
|
||||
return printer;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -754,7 +740,7 @@ request_password (GtkPrintBackend *backend,
|
||||
}
|
||||
|
||||
void
|
||||
gtk_print_backend_destroy (GtkPrintBackend *print_backend)
|
||||
gtk_print_backend_destroy (GtkPrintBackend *backend)
|
||||
{
|
||||
/* The lifecycle of print backends and printers are tied, such that
|
||||
* the backend owns the printers, but the printers also ref the backend.
|
||||
@@ -762,5 +748,5 @@ gtk_print_backend_destroy (GtkPrintBackend *print_backend)
|
||||
* will be around. However, this results in a cycle, which we break
|
||||
* with this call, which causes the print backend to release its printers.
|
||||
*/
|
||||
g_object_run_dispose (G_OBJECT (print_backend));
|
||||
g_object_run_dispose (G_OBJECT (backend));
|
||||
}
|
||||
|
||||
@@ -149,6 +149,8 @@ GType gtk_print_backend_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GList *gtk_print_backend_get_printer_list (GtkPrintBackend *print_backend);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GListModel *gtk_print_backend_get_printers (GtkPrintBackend *print_backend);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_print_backend_printer_list_is_done (GtkPrintBackend *print_backend);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkPrinter *gtk_print_backend_find_printer (GtkPrintBackend *print_backend,
|
||||
|
||||
+2
-2
@@ -169,7 +169,7 @@ gtk_printer_class_init (GtkPrinterClass *class)
|
||||
g_param_spec_string ("icon-name",
|
||||
P_("Icon Name"),
|
||||
P_("The icon name to use for the printer"),
|
||||
"",
|
||||
"printer",
|
||||
GTK_PARAM_READABLE));
|
||||
g_object_class_install_property (G_OBJECT_CLASS (class),
|
||||
PROP_JOB_COUNT,
|
||||
@@ -340,7 +340,7 @@ gtk_printer_get_property (GObject *object,
|
||||
if (priv->icon_name)
|
||||
g_value_set_string (value, priv->icon_name);
|
||||
else
|
||||
g_value_set_static_string (value, "");
|
||||
g_value_set_static_string (value, "printer");
|
||||
break;
|
||||
case PROP_JOB_COUNT:
|
||||
g_value_set_int (value, priv->job_count);
|
||||
|
||||
@@ -43,8 +43,6 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtkprogressbar
|
||||
* @Short_description: A widget which indicates progress visually
|
||||
|
||||
@@ -34,8 +34,6 @@
|
||||
#include "gsk/gskroundedrectprivate.h"
|
||||
#include <gdk/gdktextureprivate.h>
|
||||
|
||||
#include "fallback-c89.c"
|
||||
|
||||
static void
|
||||
gtk_do_render_icon (GtkStyleContext *context,
|
||||
cairo_t *cr,
|
||||
|
||||
@@ -43,11 +43,6 @@
|
||||
|
||||
#include "gsk/gskroundedrectprivate.h"
|
||||
|
||||
/* this is in case round() is not provided by the compiler,
|
||||
* such as in the case of C89 compilers, like MSVC
|
||||
*/
|
||||
#include "fallback-c89.c"
|
||||
|
||||
static void
|
||||
gtk_theming_background_snapshot_color (GtkCssBoxes *boxes,
|
||||
GtkSnapshot *snapshot,
|
||||
|
||||
@@ -39,11 +39,6 @@
|
||||
|
||||
#include "gsk/gskroundedrectprivate.h"
|
||||
|
||||
/* this is in case round() is not provided by the compiler,
|
||||
* such as in the case of C89 compilers, like MSVC
|
||||
*/
|
||||
#include "fallback-c89.c"
|
||||
|
||||
typedef struct _GtkBorderImage GtkBorderImage;
|
||||
|
||||
struct _GtkBorderImage {
|
||||
|
||||
@@ -32,8 +32,6 @@
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkbuildable.h"
|
||||
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtkrevealer
|
||||
* @Short_description: Hide and show with animation
|
||||
|
||||
+351
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Copyright © 2019 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 <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#include "gtkset.h"
|
||||
|
||||
/* Store a set of unsigned integers as a sorted array of ranges.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint first;
|
||||
guint n_items;
|
||||
} Range;
|
||||
|
||||
struct _GtkSet
|
||||
{
|
||||
GArray *ranges;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkSet *set;
|
||||
Range *current;
|
||||
int idx;
|
||||
guint pos;
|
||||
} GtkRealSetIter;
|
||||
|
||||
GtkSet *
|
||||
gtk_set_new (void)
|
||||
{
|
||||
GtkSet *set;
|
||||
|
||||
set = g_new (GtkSet, 1);
|
||||
set->ranges = g_array_new (FALSE, FALSE, sizeof (Range));
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
GtkSet *
|
||||
gtk_set_copy (GtkSet *set)
|
||||
{
|
||||
GtkSet *copy;
|
||||
|
||||
copy = g_new (GtkSet, 1);
|
||||
copy->ranges = g_array_copy (set->ranges);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_free (GtkSet *set)
|
||||
{
|
||||
g_array_free (set->ranges, TRUE);
|
||||
g_free (set);
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_set_contains (GtkSet *set,
|
||||
guint item)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
|
||||
if (item < r->first)
|
||||
return FALSE;
|
||||
|
||||
if (item < r->first + r->n_items)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_remove_all (GtkSet *set)
|
||||
{
|
||||
g_array_set_size (set->ranges, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
range_compare (Range *r, Range *s)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (r->first + r->n_items < s->first)
|
||||
ret = -1;
|
||||
else if (s->first + s->n_items < r->first)
|
||||
ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_add_range (GtkSet *set,
|
||||
guint first_item,
|
||||
guint n_items)
|
||||
{
|
||||
int i;
|
||||
Range s;
|
||||
int first = -1;
|
||||
int last = -1;
|
||||
|
||||
s.first = first_item;
|
||||
s.n_items = n_items;
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
int cmp = range_compare (&s, r);
|
||||
|
||||
if (cmp < 0)
|
||||
break;
|
||||
|
||||
if (cmp == 0)
|
||||
{
|
||||
if (first < 0)
|
||||
first = i;
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (first > -1)
|
||||
{
|
||||
Range *r;
|
||||
guint start;
|
||||
guint end;
|
||||
|
||||
r = &g_array_index (set->ranges, Range, first);
|
||||
start = MIN (s.first, r->first);
|
||||
|
||||
r = &g_array_index (set->ranges, Range, last);
|
||||
end = MAX (s.first + s.n_items - 1, r->first + r->n_items - 1);
|
||||
|
||||
s.first = start;
|
||||
s.n_items = end - start + 1;
|
||||
|
||||
g_array_remove_range (set->ranges, first, last - first + 1);
|
||||
g_array_insert_val (set->ranges, first, s);
|
||||
}
|
||||
else
|
||||
g_array_insert_val (set->ranges, i, s);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_remove_range (GtkSet *set,
|
||||
guint first_item,
|
||||
guint n_items)
|
||||
{
|
||||
Range s;
|
||||
int i;
|
||||
int first = -1;
|
||||
int last = -1;
|
||||
|
||||
s.first = first_item;
|
||||
s.n_items = n_items;
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
int cmp = range_compare (&s, r);
|
||||
|
||||
if (cmp < 0)
|
||||
break;
|
||||
|
||||
if (cmp == 0)
|
||||
{
|
||||
if (first < 0)
|
||||
first = i;
|
||||
last = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (first > -1)
|
||||
{
|
||||
Range *r;
|
||||
Range a[2];
|
||||
int k = 0;
|
||||
|
||||
r = &g_array_index (set->ranges, Range, first);
|
||||
if (r->first < s.first)
|
||||
{
|
||||
a[k].first = r->first;
|
||||
a[k].n_items = s.first - r->first;
|
||||
k++;
|
||||
}
|
||||
r = &g_array_index (set->ranges, Range, last);
|
||||
if (r->first + r->n_items > s.first + s.n_items)
|
||||
{
|
||||
a[k].first = s.first + s.n_items;
|
||||
a[k].n_items = r->first + r->n_items - a[k].first;
|
||||
k++;
|
||||
}
|
||||
g_array_remove_range (set->ranges, first, last - first + 1);
|
||||
if (k > 0)
|
||||
g_array_insert_vals (set->ranges, first, a, k);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_find_range (GtkSet *set,
|
||||
guint position,
|
||||
guint upper_bound,
|
||||
guint *start,
|
||||
guint *n_items,
|
||||
gboolean *contained)
|
||||
{
|
||||
int i;
|
||||
int last = 0;
|
||||
|
||||
if (position >= upper_bound)
|
||||
{
|
||||
*start = 0;
|
||||
*n_items = 0;
|
||||
*contained = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
|
||||
if (position < r->first)
|
||||
{
|
||||
*start = last;
|
||||
*n_items = r->first - last;
|
||||
*contained = FALSE;
|
||||
|
||||
return;
|
||||
}
|
||||
else if (r->first <= position && position < r->first + r->n_items)
|
||||
{
|
||||
*start = r->first;
|
||||
*n_items = r->n_items;
|
||||
*contained = TRUE;
|
||||
|
||||
return;
|
||||
}
|
||||
else
|
||||
last = r->first + r->n_items;
|
||||
}
|
||||
|
||||
*start = last;
|
||||
*n_items = upper_bound - last;
|
||||
*contained = FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_add_item (GtkSet *set,
|
||||
guint item)
|
||||
{
|
||||
gtk_set_add_range (set, item, 1);
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_remove_item (GtkSet *set,
|
||||
guint item)
|
||||
{
|
||||
gtk_set_remove_range (set, item, 1);
|
||||
}
|
||||
|
||||
/* This is peculiar operation: Replace every number n >= first by n + shift
|
||||
* This is only supported for negative shifts if the shifting does not cause
|
||||
* any ranges to overlap.
|
||||
*/
|
||||
void
|
||||
gtk_set_shift (GtkSet *set,
|
||||
guint first,
|
||||
int shift)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
if (r->first >= first)
|
||||
r->first += shift;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gtk_set_iter_init (GtkSetIter *iter,
|
||||
GtkSet *set)
|
||||
{
|
||||
GtkRealSetIter *ri = (GtkRealSetIter *)iter;
|
||||
|
||||
ri->set = set;
|
||||
ri->idx = -1;
|
||||
ri->current = 0;
|
||||
}
|
||||
|
||||
gboolean
|
||||
gtk_set_iter_next (GtkSetIter *iter,
|
||||
guint *item)
|
||||
{
|
||||
GtkRealSetIter *ri = (GtkRealSetIter *)iter;
|
||||
|
||||
if (ri->idx == -1)
|
||||
{
|
||||
next_range:
|
||||
ri->idx++;
|
||||
|
||||
if (ri->idx == ri->set->ranges->len)
|
||||
return FALSE;
|
||||
|
||||
ri->current = &g_array_index (ri->set->ranges, Range, ri->idx);
|
||||
ri->pos = ri->current->first;
|
||||
}
|
||||
else
|
||||
{
|
||||
ri->pos++;
|
||||
if (ri->pos == ri->current->first + ri->current->n_items)
|
||||
goto next_range;
|
||||
}
|
||||
|
||||
*item = ri->pos;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void
|
||||
gtk_set_dump (GtkSet *set)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < set->ranges->len; i++)
|
||||
{
|
||||
Range *r = &g_array_index (set->ranges, Range, i);
|
||||
g_print (" %u:%u", r->first, r->n_items);
|
||||
}
|
||||
g_print ("\n");
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright © 2019 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 <mclasen@redhat.com>
|
||||
*/
|
||||
|
||||
#ifndef __GTK_SET_H__
|
||||
#define __GTK_SET_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
typedef struct _GtkSet GtkSet;
|
||||
typedef struct _GtkSetIter GtkSetIter;
|
||||
|
||||
struct _GtkSetIter
|
||||
{
|
||||
gpointer dummy1;
|
||||
gpointer dummy2;
|
||||
int dummy3;
|
||||
int dummy4;
|
||||
};
|
||||
|
||||
GtkSet *gtk_set_new (void);
|
||||
void gtk_set_free (GtkSet *set);
|
||||
GtkSet *gtk_set_copy (GtkSet *set);
|
||||
|
||||
gboolean gtk_set_contains (GtkSet *set,
|
||||
guint item);
|
||||
|
||||
void gtk_set_remove_all (GtkSet *set);
|
||||
void gtk_set_add_item (GtkSet *set,
|
||||
guint item);
|
||||
void gtk_set_remove_item (GtkSet *set,
|
||||
guint item);
|
||||
void gtk_set_add_range (GtkSet *set,
|
||||
guint first,
|
||||
guint n);
|
||||
void gtk_set_remove_range (GtkSet *set,
|
||||
guint first,
|
||||
guint n);
|
||||
void gtk_set_find_range (GtkSet *set,
|
||||
guint position,
|
||||
guint upper_bound,
|
||||
guint *start,
|
||||
guint *n_items,
|
||||
gboolean *contained);
|
||||
|
||||
void gtk_set_shift (GtkSet *set,
|
||||
guint first,
|
||||
int shift);
|
||||
|
||||
void gtk_set_iter_init (GtkSetIter *iter,
|
||||
GtkSet *set);
|
||||
gboolean gtk_set_iter_next (GtkSetIter *iter,
|
||||
guint *item);
|
||||
|
||||
#endif /* __GTK_SET_H__ */
|
||||
@@ -71,8 +71,6 @@
|
||||
|
||||
#include "a11y/gtkswitchaccessible.h"
|
||||
|
||||
#include "fallback-c89.c"
|
||||
|
||||
typedef struct _GtkSwitchClass GtkSwitchClass;
|
||||
|
||||
/**
|
||||
|
||||
@@ -73,8 +73,6 @@
|
||||
#include <cairo-gobject.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtktext
|
||||
* @Short_description: A simple single-line text entry field
|
||||
|
||||
@@ -90,9 +90,6 @@
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
/* for the use of round() */
|
||||
#include "fallback-c89.c"
|
||||
|
||||
/**
|
||||
* SECTION:gtkwidget
|
||||
* @Short_description: Base class for all widgets
|
||||
|
||||
@@ -96,12 +96,14 @@ variant_editor_new (const GVariantType *type,
|
||||
else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
|
||||
{
|
||||
editor = gtk_entry_new ();
|
||||
gtk_editable_set_width_chars (GTK_EDITABLE (editor), 10);
|
||||
g_signal_connect (editor, "notify::text", G_CALLBACK (variant_editor_changed_cb), d);
|
||||
}
|
||||
else
|
||||
{
|
||||
editor = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
entry = gtk_entry_new ();
|
||||
gtk_editable_set_width_chars (GTK_EDITABLE (entry), 10);
|
||||
gtk_box_append (GTK_BOX (editor), entry);
|
||||
label = gtk_label_new (g_variant_type_peek_string (type));
|
||||
gtk_box_append (GTK_BOX (editor), label);
|
||||
@@ -284,7 +286,8 @@ constructed (GObject *object)
|
||||
row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
activate = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
gtk_box_append (GTK_BOX (row), activate);
|
||||
gtk_size_group_add_widget (r->priv->sg, activate);
|
||||
if (r->priv->sg)
|
||||
gtk_size_group_add_widget (r->priv->sg, activate);
|
||||
|
||||
r->priv->activate_button = gtk_button_new_with_label (_("Activate"));
|
||||
g_signal_connect (r->priv->activate_button, "clicked", G_CALLBACK (activate_action), r);
|
||||
@@ -307,7 +310,8 @@ constructed (GObject *object)
|
||||
r->priv->state_type = g_variant_type_copy (g_variant_get_type (state));
|
||||
row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 10);
|
||||
label = gtk_label_new (_("Set State"));
|
||||
gtk_size_group_add_widget (r->priv->sg, label);
|
||||
if (r->priv->sg)
|
||||
gtk_size_group_add_widget (r->priv->sg, label);
|
||||
gtk_box_append (GTK_BOX (row), label);
|
||||
r->priv->state_entry = variant_editor_new (r->priv->state_type, state_changed, r);
|
||||
variant_editor_set_value (r->priv->state_entry, state);
|
||||
@@ -327,7 +331,7 @@ finalize (GObject *object)
|
||||
GtkInspectorActionEditor *r = GTK_INSPECTOR_ACTION_EDITOR (object);
|
||||
|
||||
g_free (r->priv->name);
|
||||
g_object_unref (r->priv->sg);
|
||||
g_clear_object (&r->priv->sg);
|
||||
if (r->priv->state_type)
|
||||
g_variant_type_free (r->priv->state_type);
|
||||
g_signal_handlers_disconnect_by_func (r->priv->group, action_enabled_changed_cb, r);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
#include "action-holder.h"
|
||||
|
||||
struct _ActionHolder {
|
||||
GObject instance;
|
||||
|
||||
GActionGroup *group;
|
||||
char *name;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ActionHolder, action_holder, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
action_holder_init (ActionHolder *holder)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
action_holder_finalize (GObject *object)
|
||||
{
|
||||
ActionHolder *holder = ACTION_HOLDER (object);
|
||||
|
||||
g_object_unref (holder->group);
|
||||
g_free (holder->name);
|
||||
|
||||
G_OBJECT_CLASS (action_holder_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
action_holder_class_init (ActionHolderClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->finalize = action_holder_finalize;
|
||||
}
|
||||
|
||||
ActionHolder *
|
||||
action_holder_new (GActionGroup *group,
|
||||
const char *name)
|
||||
{
|
||||
ActionHolder *holder;
|
||||
|
||||
holder = g_object_new (ACTION_TYPE_HOLDER, NULL);
|
||||
|
||||
holder->group = g_object_ref (group);
|
||||
holder->name = g_strdup (name);
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
GActionGroup *
|
||||
action_holder_get_group (ActionHolder *holder)
|
||||
{
|
||||
return holder->group;
|
||||
}
|
||||
|
||||
const char *
|
||||
action_holder_get_name (ActionHolder *holder)
|
||||
{
|
||||
return holder->name;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
#ifndef __ACTION_HOLDER_H__
|
||||
#define __ACTION_HOLDER_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define ACTION_TYPE_HOLDER (action_holder_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ActionHolder, action_holder, ACTION, HOLDER, GObject)
|
||||
|
||||
ActionHolder * action_holder_new (GActionGroup *group,
|
||||
const char *name);
|
||||
|
||||
GActionGroup *action_holder_get_group (ActionHolder *holder);
|
||||
const char *action_holder_get_name (ActionHolder *holder);
|
||||
|
||||
#endif /* __ACTION_HOLDER_H__ */
|
||||
+232
-150
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "actions.h"
|
||||
#include "action-editor.h"
|
||||
#include "action-holder.h"
|
||||
|
||||
#include "gtkapplication.h"
|
||||
#include "gtkapplicationwindow.h"
|
||||
@@ -37,13 +38,11 @@
|
||||
struct _GtkInspectorActionsPrivate
|
||||
{
|
||||
GtkWidget *list;
|
||||
GtkSizeGroup *name;
|
||||
GtkSizeGroup *enabled;
|
||||
GtkSizeGroup *parameter;
|
||||
GtkSizeGroup *state;
|
||||
GtkSizeGroup *activate;
|
||||
GActionGroup *group;
|
||||
GtkWidget *button;
|
||||
|
||||
GActionGroup *group;
|
||||
GListModel *actions;
|
||||
GtkColumnViewColumn *name;
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -61,105 +60,170 @@ gtk_inspector_actions_init (GtkInspectorActions *sl)
|
||||
}
|
||||
|
||||
static void
|
||||
add_action (GtkInspectorActions *sl,
|
||||
GActionGroup *group,
|
||||
const gchar *name)
|
||||
action_added_cb (GActionGroup *group,
|
||||
const gchar *action_name,
|
||||
GtkInspectorActions *sl)
|
||||
{
|
||||
gboolean enabled;
|
||||
const gchar *parameter;
|
||||
GVariant *state;
|
||||
gchar *state_string;
|
||||
GtkWidget *row;
|
||||
GtkWidget *label;
|
||||
GtkWidget *box;
|
||||
char *key = g_strdup (name);
|
||||
GtkWidget *editor;
|
||||
ActionHolder *holder = action_holder_new (group, action_name);
|
||||
g_list_store_append (G_LIST_STORE (sl->priv->actions), holder);
|
||||
g_object_unref (holder);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
setup_name_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_list_item_set_child (list_item, label);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_name_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
gpointer item;
|
||||
GtkWidget *label;
|
||||
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
label = gtk_list_item_get_child (list_item);
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (label), action_holder_get_name (ACTION_HOLDER (item)));
|
||||
}
|
||||
|
||||
static void
|
||||
setup_enabled_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.5);
|
||||
gtk_list_item_set_child (list_item, label);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_enabled_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
gpointer item;
|
||||
GtkWidget *label;
|
||||
GActionGroup *group;
|
||||
const char *name;
|
||||
gboolean enabled;
|
||||
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
label = gtk_list_item_get_child (list_item);
|
||||
|
||||
group = action_holder_get_group (ACTION_HOLDER (item));
|
||||
name = action_holder_get_name (ACTION_HOLDER (item));
|
||||
enabled = g_action_group_get_action_enabled (group, name);
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (label), enabled ? "+" : "-");
|
||||
}
|
||||
|
||||
static void
|
||||
setup_parameter_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.5);
|
||||
gtk_list_item_set_child (list_item, label);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (label), "cell");
|
||||
}
|
||||
|
||||
static void
|
||||
bind_parameter_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
gpointer item;
|
||||
GtkWidget *label;
|
||||
GActionGroup *group;
|
||||
const char *name;
|
||||
const char *parameter;
|
||||
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
label = gtk_list_item_get_child (list_item);
|
||||
|
||||
group = action_holder_get_group (ACTION_HOLDER (item));
|
||||
name = action_holder_get_name (ACTION_HOLDER (item));
|
||||
parameter = (const gchar *)g_action_group_get_action_parameter_type (group, name);
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (label), parameter);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_state_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_widget_set_margin_start (label, 5);
|
||||
gtk_widget_set_margin_end (label, 5);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_list_item_set_child (list_item, label);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (label), "cell");
|
||||
}
|
||||
|
||||
static void
|
||||
bind_state_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
gpointer item;
|
||||
GtkWidget *label;
|
||||
GActionGroup *group;
|
||||
const char *name;
|
||||
GVariant *state;
|
||||
char *state_string;
|
||||
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
label = gtk_list_item_get_child (list_item);
|
||||
|
||||
group = action_holder_get_group (ACTION_HOLDER (item));
|
||||
name = action_holder_get_name (ACTION_HOLDER (item));
|
||||
state = g_action_group_get_action_state (group, name);
|
||||
if (state)
|
||||
state_string = g_variant_print (state, FALSE);
|
||||
else
|
||||
state_string = g_strdup ("");
|
||||
|
||||
row = gtk_list_box_row_new ();
|
||||
g_object_set_data_full (G_OBJECT (row), "key", key, g_free);
|
||||
|
||||
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
|
||||
|
||||
label = gtk_label_new (name);
|
||||
gtk_widget_add_css_class (label, "cell");
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_size_group_add_widget (sl->priv->name, label);
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
|
||||
label = gtk_label_new (enabled ? "+" : "-");
|
||||
gtk_widget_add_css_class (label, "cell");
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_CENTER);
|
||||
gtk_size_group_add_widget (sl->priv->enabled, label);
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
|
||||
g_object_set_data (G_OBJECT (row), "enabled", label);
|
||||
|
||||
label = gtk_label_new (parameter);
|
||||
gtk_widget_add_css_class (label, "cell");
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_size_group_add_widget (sl->priv->parameter, label);
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
|
||||
label = gtk_label_new (state_string);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_widget_add_css_class (label, "cell");
|
||||
gtk_size_group_add_widget (sl->priv->state, label);
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
g_object_set_data (G_OBJECT (row), "state", label);
|
||||
|
||||
editor = gtk_inspector_action_editor_new (group, name, sl->priv->activate);
|
||||
gtk_widget_add_css_class (editor, "cell");
|
||||
gtk_box_append (GTK_BOX (box), editor);
|
||||
g_object_set_data (G_OBJECT (row), "editor", editor);
|
||||
|
||||
gtk_list_box_insert (GTK_LIST_BOX (sl->priv->list), row, -1);
|
||||
gtk_label_set_label (GTK_LABEL (label), state_string);
|
||||
|
||||
g_free (state_string);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
find_row (GtkInspectorActions *sl,
|
||||
const char *action_name)
|
||||
{
|
||||
GtkWidget *row = NULL;
|
||||
GtkWidget *widget;
|
||||
const char *key;
|
||||
|
||||
for (widget = gtk_widget_get_first_child (sl->priv->list);
|
||||
widget;
|
||||
widget = gtk_widget_get_next_sibling (widget))
|
||||
{
|
||||
if (!GTK_IS_LIST_BOX_ROW (widget))
|
||||
continue;
|
||||
|
||||
key = g_object_get_data (G_OBJECT (widget), "key");
|
||||
if (g_str_equal (key, action_name))
|
||||
{
|
||||
row = widget;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return row;
|
||||
if (state)
|
||||
g_variant_unref (state);
|
||||
}
|
||||
|
||||
static void
|
||||
action_added_cb (GActionGroup *group,
|
||||
const gchar *action_name,
|
||||
GtkInspectorActions *sl)
|
||||
bind_changes_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
add_action (sl, group, action_name);
|
||||
gpointer item;
|
||||
GActionGroup *group;
|
||||
const char *name;
|
||||
GtkWidget *editor;
|
||||
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
|
||||
group = action_holder_get_group (ACTION_HOLDER (item));
|
||||
name = action_holder_get_name (ACTION_HOLDER (item));
|
||||
|
||||
editor = gtk_inspector_action_editor_new (group, name, NULL);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (editor), "cell");
|
||||
gtk_list_item_set_child (list_item, editor);
|
||||
}
|
||||
|
||||
static void
|
||||
unbind_changes_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
gtk_list_item_set_child (list_item, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -167,21 +231,37 @@ action_removed_cb (GActionGroup *group,
|
||||
const gchar *action_name,
|
||||
GtkInspectorActions *sl)
|
||||
{
|
||||
GtkWidget *row;
|
||||
int i;
|
||||
|
||||
row = find_row (sl, action_name);
|
||||
if (row)
|
||||
gtk_list_box_remove (GTK_LIST_BOX (sl->priv->list), row);
|
||||
for (i = 0; i < g_list_model_get_n_items (sl->priv->actions); i++)
|
||||
{
|
||||
ActionHolder *holder = g_list_model_get_item (sl->priv->actions, i);
|
||||
|
||||
if (group == action_holder_get_group (holder) &&
|
||||
strcmp (action_name, action_holder_get_name (holder)) == 0)
|
||||
g_list_store_remove (G_LIST_STORE (sl->priv->actions), i);
|
||||
|
||||
g_object_unref (holder);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_row_enabled (GtkWidget *row,
|
||||
gboolean enabled)
|
||||
notify_action_changed (GtkInspectorActions *sl,
|
||||
GActionGroup *group,
|
||||
const char *action_name)
|
||||
{
|
||||
GtkWidget *label;
|
||||
int i;
|
||||
|
||||
label = GTK_WIDGET (g_object_get_data (G_OBJECT (row), "enabled"));
|
||||
gtk_label_set_label (GTK_LABEL (label), enabled ? "+" : "-" );
|
||||
for (i = 0; i < g_list_model_get_n_items (sl->priv->actions); i++)
|
||||
{
|
||||
ActionHolder *holder = g_list_model_get_item (sl->priv->actions, i);
|
||||
|
||||
if (group == action_holder_get_group (holder) &&
|
||||
strcmp (action_name, action_holder_get_name (holder)) == 0)
|
||||
g_list_model_items_changed (sl->priv->actions, i, 1, 1);
|
||||
|
||||
g_object_unref (holder);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -190,26 +270,7 @@ action_enabled_changed_cb (GActionGroup *group,
|
||||
gboolean enabled,
|
||||
GtkInspectorActions *sl)
|
||||
{
|
||||
GtkWidget *row;
|
||||
|
||||
row = find_row (sl, action_name);
|
||||
set_row_enabled (row, enabled);
|
||||
}
|
||||
|
||||
static void
|
||||
set_row_state (GtkWidget *row,
|
||||
GVariant *state)
|
||||
{
|
||||
gchar *state_string;
|
||||
GtkWidget *label;
|
||||
|
||||
if (state)
|
||||
state_string = g_variant_print (state, FALSE);
|
||||
else
|
||||
state_string = g_strdup ("");
|
||||
label = GTK_WIDGET (g_object_get_data (G_OBJECT (row), "state"));
|
||||
gtk_label_set_label (GTK_LABEL (label), state_string);
|
||||
g_free (state_string);
|
||||
notify_action_changed (sl, group, action_name);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -218,35 +279,14 @@ action_state_changed_cb (GActionGroup *group,
|
||||
GVariant *state,
|
||||
GtkInspectorActions *sl)
|
||||
{
|
||||
GtkWidget *row;
|
||||
|
||||
row = find_row (sl, action_name);
|
||||
set_row_state (row, state);
|
||||
notify_action_changed (sl, group, action_name);
|
||||
}
|
||||
|
||||
static void
|
||||
refresh_all (GtkInspectorActions *sl)
|
||||
{
|
||||
GtkWidget *widget;
|
||||
|
||||
for (widget = gtk_widget_get_first_child (sl->priv->list);
|
||||
widget;
|
||||
widget = gtk_widget_get_next_sibling (widget))
|
||||
{
|
||||
const char *name = g_object_get_data (G_OBJECT (widget), "key");
|
||||
gboolean enabled;
|
||||
GVariant *state;
|
||||
GtkInspectorActionEditor *r;
|
||||
|
||||
enabled = g_action_group_get_action_enabled (sl->priv->group, name);
|
||||
state = g_action_group_get_action_state (sl->priv->group, name);
|
||||
|
||||
set_row_enabled (widget, enabled);
|
||||
set_row_state (widget, state);
|
||||
|
||||
r = (GtkInspectorActionEditor*)g_object_get_data (G_OBJECT (widget), "editor");
|
||||
gtk_inspector_action_editor_update (r, enabled, state);
|
||||
}
|
||||
guint n = g_list_model_get_n_items (sl->priv->actions);
|
||||
g_list_model_items_changed (sl->priv->actions, 0, n, n);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -283,7 +323,7 @@ add_group (GtkInspectorActions *sl,
|
||||
|
||||
names = g_action_group_list_actions (group);
|
||||
for (i = 0; names[i]; i++)
|
||||
add_action (sl, group, names[i]);
|
||||
action_added_cb (group, names[i], sl);
|
||||
g_strfreev (names);
|
||||
|
||||
g_set_object (&sl->priv->group, group);
|
||||
@@ -305,7 +345,6 @@ gtk_inspector_actions_set_object (GtkInspectorActions *sl,
|
||||
{
|
||||
GtkWidget *stack;
|
||||
GtkStackPage *page;
|
||||
GtkWidget *child;
|
||||
|
||||
stack = gtk_widget_get_parent (GTK_WIDGET (sl));
|
||||
page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (sl));
|
||||
@@ -315,8 +354,7 @@ gtk_inspector_actions_set_object (GtkInspectorActions *sl,
|
||||
if (sl->priv->group)
|
||||
remove_group (sl, page, sl->priv->group);
|
||||
|
||||
while ((child = gtk_widget_get_first_child (sl->priv->list)))
|
||||
gtk_list_box_remove (GTK_LIST_BOX (sl->priv->list), child);
|
||||
g_list_store_remove_all (G_LIST_STORE (sl->priv->actions));
|
||||
|
||||
if (GTK_IS_APPLICATION (object))
|
||||
add_group (sl, page, G_ACTION_GROUP (object));
|
||||
@@ -328,6 +366,8 @@ gtk_inspector_actions_set_object (GtkInspectorActions *sl,
|
||||
if (muxer)
|
||||
add_group (sl, page, G_ACTION_GROUP (muxer));
|
||||
}
|
||||
|
||||
gtk_column_view_sort_by_column (GTK_COLUMN_VIEW (sl->priv->list), sl->priv->name, GTK_SORT_ASCENDING);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -370,13 +410,48 @@ set_property (GObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
holder_name (gpointer item)
|
||||
{
|
||||
return g_strdup (action_holder_get_name (ACTION_HOLDER (item)));
|
||||
}
|
||||
|
||||
static void
|
||||
constructed (GObject *object)
|
||||
{
|
||||
GtkInspectorActions *sl = GTK_INSPECTOR_ACTIONS (object);
|
||||
GtkSorter *sorter;
|
||||
GListModel *sorted;
|
||||
GListModel *model;
|
||||
|
||||
g_signal_connect_swapped (sl->priv->button, "clicked",
|
||||
G_CALLBACK (refresh_all), sl);
|
||||
|
||||
sorter = gtk_string_sorter_new (gtk_cclosure_expression_new (G_TYPE_STRING,
|
||||
NULL,
|
||||
0, NULL,
|
||||
(GCallback)holder_name,
|
||||
NULL, NULL));
|
||||
gtk_column_view_column_set_sorter (sl->priv->name, sorter);
|
||||
g_object_unref (sorter);
|
||||
|
||||
sl->priv->actions = G_LIST_MODEL (g_list_store_new (ACTION_TYPE_HOLDER));
|
||||
sorted = G_LIST_MODEL (gtk_sort_list_model_new (sl->priv->actions,
|
||||
gtk_column_view_get_sorter (GTK_COLUMN_VIEW (sl->priv->list))));
|
||||
model = G_LIST_MODEL (gtk_no_selection_new (sorted));
|
||||
gtk_column_view_set_model (GTK_COLUMN_VIEW (sl->priv->list), model);
|
||||
g_object_unref (sorted);
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
static void
|
||||
finalize (GObject *object)
|
||||
{
|
||||
GtkInspectorActions *sl = GTK_INSPECTOR_ACTIONS (object);
|
||||
|
||||
g_object_unref (sl->priv->actions);
|
||||
|
||||
G_OBJECT_CLASS (gtk_inspector_actions_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -385,6 +460,7 @@ gtk_inspector_actions_class_init (GtkInspectorActionsClass *klass)
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->finalize = finalize;
|
||||
object_class->get_property = get_property;
|
||||
object_class->set_property = set_property;
|
||||
object_class->constructed = constructed;
|
||||
@@ -396,10 +472,16 @@ gtk_inspector_actions_class_init (GtkInspectorActionsClass *klass)
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/actions.ui");
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorActions, list);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorActions, name);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorActions, enabled);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorActions, parameter);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorActions, state);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorActions, activate);
|
||||
gtk_widget_class_bind_template_callback (widget_class, setup_name_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, bind_name_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, setup_enabled_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, bind_enabled_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, setup_parameter_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, bind_parameter_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, setup_state_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, bind_state_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, bind_changes_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, unbind_changes_cb);
|
||||
}
|
||||
|
||||
// vim: set et sw=2 ts=2:
|
||||
|
||||
+57
-76
@@ -1,98 +1,79 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface domain="gtk40">
|
||||
<object class="GtkListStore" id="model">
|
||||
<columns>
|
||||
<column type="gchararray"/>
|
||||
<column type="gchararray"/>
|
||||
<column type="gboolean"/>
|
||||
<column type="gchararray"/>
|
||||
<column type="gchararray"/>
|
||||
<column type="gpointer"/>
|
||||
</columns>
|
||||
</object>
|
||||
<template class="GtkInspectorActions" parent="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<style>
|
||||
<class name="header"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkLabel" id="name_heading">
|
||||
<property name="label" translatable="yes">Name</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="enabled_heading">
|
||||
<property name="label" translatable="yes">Enabled</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="parameter_heading">
|
||||
<property name="label" translatable="yes">Parameter Type</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="state_heading">
|
||||
<property name="label" translatable="yes">State</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="changes_heading">
|
||||
<property name="label" translatable="yes"></property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="list">
|
||||
<object class="GtkColumnView" id="list">
|
||||
<style>
|
||||
<class name="list"/>
|
||||
</style>
|
||||
<property name="selection-mode">none</property>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="name">
|
||||
<property name="title" translatable="yes">Name</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_name_cb"/>
|
||||
<signal name="bind" handler="bind_name_cb"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="enabled">
|
||||
<property name="title" translatable="yes">Enabled</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_enabled_cb"/>
|
||||
<signal name="bind" handler="bind_enabled_cb"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="parameter">
|
||||
<property name="title" translatable="yes">Parameter Type</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_parameter_cb"/>
|
||||
<signal name="bind" handler="bind_parameter_cb"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="state">
|
||||
<property name="title" translatable="yes">State</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_state_cb"/>
|
||||
<signal name="bind" handler="bind_state_cb"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="changes">
|
||||
<property name="title"></property>
|
||||
<property name="expand">1</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="bind" handler="bind_changes_cb"/>
|
||||
<signal name="unbind" handler="unbind_changes_cb"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
<object class="GtkSizeGroup" id="name">
|
||||
<property name="mode">horizontal</property>
|
||||
<widgets>
|
||||
<widget name="name_heading"/>
|
||||
</widgets>
|
||||
</object>
|
||||
<object class="GtkSizeGroup" id="enabled">
|
||||
<property name="mode">horizontal</property>
|
||||
<widgets>
|
||||
<widget name="enabled_heading"/>
|
||||
</widgets>
|
||||
</object>
|
||||
<object class="GtkSizeGroup" id="parameter">
|
||||
<property name="mode">horizontal</property>
|
||||
<widgets>
|
||||
<widget name="parameter_heading"/>
|
||||
</widgets>
|
||||
</object>
|
||||
<object class="GtkSizeGroup" id="state">
|
||||
<property name="mode">horizontal</property>
|
||||
<widgets>
|
||||
<widget name="state_heading"/>
|
||||
</widgets>
|
||||
</object>
|
||||
<object class="GtkSizeGroup" id="activate">
|
||||
<property name="mode">horizontal</property>
|
||||
</object>
|
||||
</interface>
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
/* some style for the inspector */
|
||||
|
||||
.header {
|
||||
background: lightgray;
|
||||
border: 1px solid gray;
|
||||
.list header {
|
||||
background: white;
|
||||
border: 1px solid lightgray;
|
||||
}
|
||||
|
||||
.header>* {
|
||||
.list header button {
|
||||
background: none;
|
||||
}
|
||||
|
||||
.list header button.dnd {
|
||||
background: gray;
|
||||
}
|
||||
|
||||
.list header>* {
|
||||
padding: 2px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.header sort_indicator {
|
||||
.list header sort_indicator {
|
||||
min-width: 16px;
|
||||
}
|
||||
|
||||
.header>*:not(:last-child) {
|
||||
border-right: 1px solid gray;
|
||||
.list header>*:not(:last-child) {
|
||||
border-right: 1px solid lightgray;
|
||||
}
|
||||
|
||||
.list .cell {
|
||||
|
||||
@@ -38,4 +38,7 @@ inspector_sources = files(
|
||||
'updatesoverlay.c',
|
||||
'visual.c',
|
||||
'window.c',
|
||||
'prop-holder.c',
|
||||
'resource-holder.c',
|
||||
'action-holder.c'
|
||||
)
|
||||
|
||||
@@ -336,6 +336,29 @@ object_tree_tree_view_get_children (GObject *object)
|
||||
return G_LIST_MODEL (result);
|
||||
}
|
||||
|
||||
static GListModel *
|
||||
object_tree_column_view_get_children (GObject *object)
|
||||
{
|
||||
GtkColumnView *view = GTK_COLUMN_VIEW (object);
|
||||
GListStore *result_list;
|
||||
GtkFlattenListModel *result;
|
||||
GListModel *columns, *sublist;
|
||||
|
||||
result_list = g_list_store_new (G_TYPE_LIST_MODEL);
|
||||
|
||||
columns = gtk_column_view_get_columns (view);
|
||||
g_list_store_append (result_list, columns);
|
||||
|
||||
sublist = object_tree_widget_get_children (object);
|
||||
g_list_store_append (result_list, sublist);
|
||||
g_object_unref (sublist);
|
||||
|
||||
result = gtk_flatten_list_model_new (G_TYPE_OBJECT, G_LIST_MODEL (result_list));
|
||||
g_object_unref (result_list);
|
||||
|
||||
return G_LIST_MODEL (result);
|
||||
}
|
||||
|
||||
static GListModel *
|
||||
object_tree_icon_view_get_children (GObject *object)
|
||||
{
|
||||
@@ -499,6 +522,11 @@ static const ObjectTreeClassFuncs object_tree_class_funcs[] = {
|
||||
object_tree_widget_get_parent,
|
||||
object_tree_tree_view_get_children
|
||||
},
|
||||
{
|
||||
gtk_column_view_get_type,
|
||||
object_tree_widget_get_parent,
|
||||
object_tree_column_view_get_children
|
||||
},
|
||||
{
|
||||
gtk_combo_box_get_type,
|
||||
object_tree_widget_get_parent,
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title">Type</property>
|
||||
<property name="expand">1</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_type_cb"/>
|
||||
@@ -57,6 +58,7 @@
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title">Name</property>
|
||||
<property name="expand">1</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_name_cb"/>
|
||||
@@ -68,6 +70,7 @@
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title">Label</property>
|
||||
<property name="expand">1</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_label_cb"/>
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
#include "prop-holder.h"
|
||||
|
||||
enum {
|
||||
PROP_OBJECT = 1,
|
||||
PROP_PSPEC,
|
||||
PROP_NAME,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
static GParamSpec *properties[NUM_PROPERTIES];
|
||||
|
||||
struct _PropHolder {
|
||||
GObject instance;
|
||||
|
||||
GObject *object;
|
||||
GParamSpec *pspec;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (PropHolder, prop_holder, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
prop_holder_init (PropHolder *holder)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
prop_holder_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PropHolder *holder = PROP_HOLDER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_OBJECT:
|
||||
holder->object = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
case PROP_PSPEC:
|
||||
holder->pspec = g_value_get_param (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
prop_holder_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PropHolder *holder = PROP_HOLDER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_OBJECT:
|
||||
g_value_set_object (value, holder->object);
|
||||
break;
|
||||
|
||||
case PROP_PSPEC:
|
||||
g_value_set_param (value, holder->pspec);
|
||||
break;
|
||||
|
||||
case PROP_NAME:
|
||||
g_value_set_string (value, holder->pspec->name);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
prop_holder_finalize (GObject *object)
|
||||
{
|
||||
PropHolder *holder = PROP_HOLDER (object);
|
||||
|
||||
g_object_unref (holder->object);
|
||||
|
||||
G_OBJECT_CLASS (prop_holder_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
prop_holder_class_init (PropHolderClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->finalize = prop_holder_finalize;
|
||||
object_class->set_property = prop_holder_set_property;
|
||||
object_class->get_property = prop_holder_get_property;
|
||||
|
||||
properties[PROP_OBJECT] =
|
||||
g_param_spec_object ("object", "object", "object",
|
||||
G_TYPE_OBJECT,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
properties[PROP_PSPEC] =
|
||||
g_param_spec_param ("pspec", "pspec", "pspec",
|
||||
G_TYPE_PARAM,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
properties[PROP_NAME] =
|
||||
g_param_spec_string ("name", "name", "name",
|
||||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
|
||||
}
|
||||
|
||||
PropHolder *
|
||||
prop_holder_new (GObject *object,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
PropHolder *holder;
|
||||
|
||||
holder = g_object_new (PROP_TYPE_HOLDER,
|
||||
"object", object,
|
||||
"pspec", pspec,
|
||||
NULL);
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
GObject *
|
||||
prop_holder_get_object (PropHolder *holder)
|
||||
{
|
||||
return holder->object;
|
||||
}
|
||||
|
||||
GParamSpec *
|
||||
prop_holder_get_pspec (PropHolder *holder)
|
||||
{
|
||||
return holder->pspec;
|
||||
}
|
||||
|
||||
const char *
|
||||
prop_holder_get_name (PropHolder *holder)
|
||||
{
|
||||
return holder->pspec->name;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef __PROP_HOLDER_H__
|
||||
#define __PROP_HOLDER_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define PROP_TYPE_HOLDER (prop_holder_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (PropHolder, prop_holder, PROP, HOLDER, GObject)
|
||||
|
||||
PropHolder * prop_holder_new (GObject *object,
|
||||
GParamSpec *pspeC);
|
||||
|
||||
GObject *prop_holder_get_object (PropHolder *holder);
|
||||
GParamSpec *prop_holder_get_pspec (PropHolder *holder);
|
||||
const char *prop_holder_get_name (PropHolder *holder);
|
||||
|
||||
#endif /* __PROP_HOLDER_H__ */
|
||||
+210
-199
@@ -44,6 +44,7 @@
|
||||
#include "gtkroot.h"
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkstylecontext.h"
|
||||
#include "prop-holder.h"
|
||||
|
||||
enum
|
||||
{
|
||||
@@ -52,11 +53,6 @@ enum
|
||||
PROP_SEARCH_ENTRY
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
COLUMN_NAME,
|
||||
COLUMN_ORIGIN
|
||||
} SortColumn;
|
||||
|
||||
struct _GtkInspectorPropListPrivate
|
||||
{
|
||||
GObject *object;
|
||||
@@ -64,17 +60,11 @@ struct _GtkInspectorPropListPrivate
|
||||
GtkInspectorObjectTree *object_tree;
|
||||
GtkWidget *search_entry;
|
||||
GtkWidget *search_stack;
|
||||
GtkWidget *list2;
|
||||
GtkWidget *name_sort_indicator;
|
||||
GtkWidget *origin_sort_indicator;
|
||||
GtkWidget *name_heading;
|
||||
GtkWidget *origin_heading;
|
||||
SortColumn sort_column;
|
||||
GtkSortType sort_direction;
|
||||
GtkSizeGroup *names;
|
||||
GtkSizeGroup *types;
|
||||
GtkSizeGroup *values;
|
||||
GtkSizeGroup *origins;
|
||||
GtkWidget *list;
|
||||
GtkFilter *filter;
|
||||
GtkColumnViewColumn *name;
|
||||
GtkColumnViewColumn *type;
|
||||
GtkColumnViewColumn *origin;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorPropList, gtk_inspector_prop_list, GTK_TYPE_BOX)
|
||||
@@ -94,103 +84,66 @@ show_search_entry (GtkInspectorPropList *pl)
|
||||
pl->priv->search_entry);
|
||||
}
|
||||
|
||||
static void
|
||||
apply_sort (GtkInspectorPropList *pl,
|
||||
SortColumn column,
|
||||
GtkSortType direction)
|
||||
static char *
|
||||
holder_prop (gpointer item)
|
||||
{
|
||||
const char *icon_name;
|
||||
GParamSpec *prop = prop_holder_get_pspec (PROP_HOLDER (item));
|
||||
|
||||
icon_name = direction == GTK_SORT_ASCENDING ? "pan-down-symbolic"
|
||||
: "pan-up-symbolic";
|
||||
|
||||
if (column == COLUMN_NAME)
|
||||
{
|
||||
gtk_image_clear (GTK_IMAGE (pl->priv->origin_sort_indicator));
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (pl->priv->name_sort_indicator),
|
||||
icon_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_image_clear (GTK_IMAGE (pl->priv->name_sort_indicator));
|
||||
gtk_image_set_from_icon_name (GTK_IMAGE (pl->priv->origin_sort_indicator),
|
||||
icon_name);
|
||||
}
|
||||
|
||||
pl->priv->sort_column = column;
|
||||
pl->priv->sort_direction = direction;
|
||||
|
||||
gtk_list_box_invalidate_sort (GTK_LIST_BOX (pl->priv->list2));
|
||||
return g_strdup (prop->name);
|
||||
}
|
||||
|
||||
static void
|
||||
sort_changed (GtkGestureClick *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
double y,
|
||||
GtkInspectorPropList *pl)
|
||||
static char *
|
||||
holder_type (gpointer item)
|
||||
{
|
||||
SortColumn column;
|
||||
GtkSortType direction;
|
||||
GtkWidget *widget;
|
||||
GParamSpec *prop = prop_holder_get_pspec (PROP_HOLDER (item));
|
||||
|
||||
widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture));
|
||||
if (widget == pl->priv->name_heading)
|
||||
column = COLUMN_NAME;
|
||||
else
|
||||
column = COLUMN_ORIGIN;
|
||||
|
||||
if (pl->priv->sort_column == column &&
|
||||
pl->priv->sort_direction == GTK_SORT_ASCENDING)
|
||||
direction = GTK_SORT_DESCENDING;
|
||||
else
|
||||
direction = GTK_SORT_ASCENDING;
|
||||
|
||||
apply_sort (pl, column, direction);
|
||||
return g_strdup (g_type_name (prop->value_type));
|
||||
}
|
||||
|
||||
static const char *
|
||||
row_get_column (GtkListBoxRow *row,
|
||||
SortColumn column)
|
||||
static char *
|
||||
holder_origin (gpointer item)
|
||||
{
|
||||
GParamSpec *prop = g_object_get_data (G_OBJECT (row), "pspec");
|
||||
GParamSpec *prop = prop_holder_get_pspec (PROP_HOLDER (item));
|
||||
|
||||
if (column == COLUMN_NAME)
|
||||
return prop->name;
|
||||
else
|
||||
return g_type_name (prop->owner_type);
|
||||
}
|
||||
|
||||
static int
|
||||
sort_func (GtkListBoxRow *row1,
|
||||
GtkListBoxRow *row2,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkInspectorPropList *pl = user_data;
|
||||
const char *s1 = row_get_column (row1, pl->priv->sort_column);
|
||||
const char *s2 = row_get_column (row2, pl->priv->sort_column);
|
||||
int ret = strcmp (s1, s2);
|
||||
|
||||
return pl->priv->sort_direction == GTK_SORT_ASCENDING ? ret : -ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
filter_func (GtkListBoxRow *row,
|
||||
gpointer data)
|
||||
{
|
||||
GtkInspectorPropList *pl = data;
|
||||
GParamSpec *pspec = (GParamSpec *)g_object_get_data (G_OBJECT (row), "pspec");
|
||||
const char *text = gtk_editable_get_text (GTK_EDITABLE (pl->priv->search_entry));
|
||||
|
||||
return g_str_has_prefix (pspec->name, text);
|
||||
return g_strdup (g_type_name (prop->owner_type));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_inspector_prop_list_init (GtkInspectorPropList *pl)
|
||||
{
|
||||
GtkSorter *sorter;
|
||||
|
||||
pl->priv = gtk_inspector_prop_list_get_instance_private (pl);
|
||||
gtk_widget_init_template (GTK_WIDGET (pl));
|
||||
apply_sort (pl, COLUMN_NAME, GTK_SORT_ASCENDING);
|
||||
pl->priv->filter = gtk_string_filter_new ();
|
||||
gtk_string_filter_set_match_mode (GTK_STRING_FILTER (pl->priv->filter), GTK_STRING_FILTER_MATCH_MODE_PREFIX);
|
||||
|
||||
sorter = gtk_string_sorter_new (gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
|
||||
0, NULL,
|
||||
(GCallback)holder_prop,
|
||||
NULL, NULL));
|
||||
|
||||
gtk_string_filter_set_expression (GTK_STRING_FILTER (pl->priv->filter),
|
||||
gtk_string_sorter_get_expression (GTK_STRING_SORTER (sorter)));
|
||||
|
||||
gtk_column_view_column_set_sorter (pl->priv->name, sorter);
|
||||
g_object_unref (sorter);
|
||||
|
||||
sorter = gtk_string_sorter_new (gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
|
||||
0, NULL,
|
||||
(GCallback)holder_type,
|
||||
NULL, NULL));
|
||||
|
||||
gtk_column_view_column_set_sorter (pl->priv->type, sorter);
|
||||
g_object_unref (sorter);
|
||||
|
||||
sorter = gtk_string_sorter_new (gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
|
||||
0, NULL,
|
||||
(GCallback)holder_origin,
|
||||
NULL, NULL));
|
||||
|
||||
gtk_column_view_column_set_sorter (pl->priv->origin, sorter);
|
||||
g_object_unref (sorter);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -253,6 +206,7 @@ show_object (GtkInspectorPropEditor *editor,
|
||||
gtk_inspector_object_tree_activate_object (pl->priv->object_tree, object);
|
||||
}
|
||||
|
||||
|
||||
static void cleanup_object (GtkInspectorPropList *pl);
|
||||
|
||||
static void
|
||||
@@ -265,6 +219,16 @@ finalize (GObject *object)
|
||||
G_OBJECT_CLASS (gtk_inspector_prop_list_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
update_filter (GtkInspectorPropList *pl,
|
||||
GtkSearchEntry *entry)
|
||||
{
|
||||
const char *text;
|
||||
|
||||
text = gtk_editable_get_text (GTK_EDITABLE (entry));
|
||||
gtk_string_filter_set_search (GTK_STRING_FILTER (pl->priv->filter), text);
|
||||
}
|
||||
|
||||
static void
|
||||
constructed (GObject *object)
|
||||
{
|
||||
@@ -278,10 +242,7 @@ constructed (GObject *object)
|
||||
g_signal_connect_swapped (pl->priv->search_entry, "search-started",
|
||||
G_CALLBACK (show_search_entry), pl);
|
||||
g_signal_connect_swapped (pl->priv->search_entry, "search-changed",
|
||||
G_CALLBACK (gtk_list_box_invalidate_filter), pl->priv->list2);
|
||||
|
||||
gtk_list_box_set_filter_func (GTK_LIST_BOX (pl->priv->list2), filter_func, pl, NULL);
|
||||
gtk_list_box_set_sort_func (GTK_LIST_BOX (pl->priv->list2), sort_func, pl, NULL);
|
||||
G_CALLBACK (update_filter), pl);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -298,7 +259,7 @@ update_key_capture (GtkInspectorPropList *pl)
|
||||
focus = gtk_root_get_focus (GTK_ROOT (toplevel));
|
||||
|
||||
if (GTK_IS_EDITABLE (focus) &&
|
||||
gtk_widget_is_ancestor (focus, pl->priv->list2))
|
||||
gtk_widget_is_ancestor (focus, pl->priv->list))
|
||||
capture_widget = NULL;
|
||||
else
|
||||
capture_widget = toplevel;
|
||||
@@ -344,6 +305,120 @@ unroot (GtkWidget *widget)
|
||||
GTK_WIDGET_CLASS (gtk_inspector_prop_list_parent_class)->unroot (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_name_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_list_item_set_child (list_item, label);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (label), "cell");
|
||||
}
|
||||
|
||||
static void
|
||||
bind_name_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GObject *item;
|
||||
GtkWidget *label;
|
||||
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
label = gtk_list_item_get_child (list_item);
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (label), prop_holder_get_name (PROP_HOLDER (item)));
|
||||
}
|
||||
|
||||
static void
|
||||
setup_type_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_list_item_set_child (list_item, label);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (label), "cell");
|
||||
}
|
||||
|
||||
static void
|
||||
bind_type_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GObject *item;
|
||||
GtkWidget *label;
|
||||
GParamSpec *prop;
|
||||
const char *type;
|
||||
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
label = gtk_list_item_get_child (list_item);
|
||||
|
||||
prop = prop_holder_get_pspec (PROP_HOLDER (item));
|
||||
type = g_type_name (G_PARAM_SPEC_VALUE_TYPE (prop));
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (label), type);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_origin_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GtkWidget *label;
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
||||
gtk_list_item_set_child (list_item, label);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (label), "cell");
|
||||
}
|
||||
|
||||
static void
|
||||
bind_origin_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item)
|
||||
{
|
||||
GObject *item;
|
||||
GtkWidget *label;
|
||||
GParamSpec *prop;
|
||||
const char *origin;
|
||||
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
label = gtk_list_item_get_child (list_item);
|
||||
|
||||
prop = prop_holder_get_pspec (PROP_HOLDER (item));
|
||||
origin = g_type_name (prop->owner_type);
|
||||
|
||||
gtk_label_set_label (GTK_LABEL (label), origin);
|
||||
}
|
||||
|
||||
static void
|
||||
bind_value_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item,
|
||||
gpointer data)
|
||||
{
|
||||
GObject *item;
|
||||
GtkWidget *widget;
|
||||
GObject *object;
|
||||
const char *name;
|
||||
|
||||
item = gtk_list_item_get_item (list_item);
|
||||
|
||||
object = prop_holder_get_object (PROP_HOLDER (item));
|
||||
name = prop_holder_get_name (PROP_HOLDER (item));
|
||||
|
||||
widget = gtk_inspector_prop_editor_new (object, name, NULL);
|
||||
g_signal_connect (widget, "show-object", G_CALLBACK (show_object), data);
|
||||
gtk_list_item_set_child (list_item, widget);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (widget), "cell");
|
||||
}
|
||||
|
||||
static void
|
||||
unbind_value_cb (GtkSignalListItemFactory *factory,
|
||||
GtkListItem *list_item,
|
||||
gpointer data)
|
||||
{
|
||||
gtk_list_item_set_child (list_item, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_inspector_prop_list_class_init (GtkInspectorPropListClass *klass)
|
||||
{
|
||||
@@ -369,16 +444,18 @@ gtk_inspector_prop_list_class_init (GtkInspectorPropListClass *klass)
|
||||
GTK_TYPE_WIDGET, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gtk/libgtk/inspector/prop-list.ui");
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, list2);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, names);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, types);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, values);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, origins);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, name_heading);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, name_sort_indicator);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, origin_heading);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, origin_sort_indicator);
|
||||
gtk_widget_class_bind_template_callback (widget_class, sort_changed);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, list);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, name);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, type);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorPropList, origin);
|
||||
gtk_widget_class_bind_template_callback (widget_class, setup_name_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, bind_name_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, setup_type_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, bind_type_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, setup_origin_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, bind_origin_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, bind_value_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, unbind_value_cb);
|
||||
}
|
||||
|
||||
/* Like g_strdup_value_contents, but keeps the type name separate */
|
||||
@@ -483,88 +560,6 @@ strdup_value_contents (const GValue *value,
|
||||
}
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
gtk_inspector_prop_list_create_row (GtkInspectorPropList *pl,
|
||||
GParamSpec *prop)
|
||||
{
|
||||
GValue gvalue = {0};
|
||||
gchar *value;
|
||||
gchar *type;
|
||||
gchar *attribute = NULL;
|
||||
gboolean writable;
|
||||
GtkWidget *row;
|
||||
GtkWidget *box;
|
||||
GtkWidget *label;
|
||||
GtkWidget *widget;
|
||||
|
||||
g_value_init (&gvalue, prop->value_type);
|
||||
g_object_get_property (pl->priv->object, prop->name, &gvalue);
|
||||
|
||||
strdup_value_contents (&gvalue, &value, &type);
|
||||
|
||||
if (GTK_IS_CELL_RENDERER (pl->priv->object))
|
||||
{
|
||||
gpointer *layout;
|
||||
GtkCellArea *area;
|
||||
gint column = -1;
|
||||
|
||||
area = NULL;
|
||||
layout = g_object_get_data (pl->priv->object, "gtk-inspector-cell-layout");
|
||||
if (layout)
|
||||
area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (layout));
|
||||
if (area)
|
||||
column = gtk_cell_area_attribute_get_column (area,
|
||||
GTK_CELL_RENDERER (pl->priv->object),
|
||||
prop->name);
|
||||
|
||||
if (column != -1)
|
||||
attribute = g_strdup_printf ("%d", column);
|
||||
}
|
||||
|
||||
writable = ((prop->flags & G_PARAM_WRITABLE) != 0) &&
|
||||
((prop->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
|
||||
|
||||
row = gtk_list_box_row_new ();
|
||||
gtk_list_box_row_set_activatable (GTK_LIST_BOX_ROW (row), FALSE);
|
||||
g_object_set_data (G_OBJECT (row), "pspec", prop);
|
||||
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box);
|
||||
|
||||
label = gtk_label_new (prop->name);
|
||||
gtk_widget_add_css_class (label, "cell");
|
||||
gtk_widget_set_sensitive (label, writable);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_size_group_add_widget (pl->priv->names, label);
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
|
||||
label = gtk_label_new (type ? type : "");
|
||||
gtk_widget_add_css_class (label, "cell");
|
||||
gtk_widget_set_sensitive (label, writable);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_size_group_add_widget (pl->priv->types, label);
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
|
||||
label = gtk_label_new (g_type_name (prop->owner_type));
|
||||
gtk_widget_add_css_class (label, "cell");
|
||||
gtk_widget_set_sensitive (label, writable);
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_size_group_add_widget (pl->priv->origins, label);
|
||||
gtk_box_append (GTK_BOX (box), label);
|
||||
|
||||
widget = gtk_inspector_prop_editor_new (pl->priv->object, prop->name, pl->priv->values);
|
||||
gtk_widget_add_css_class (widget, "cell");
|
||||
gtk_box_append (GTK_BOX (box), widget);
|
||||
g_signal_connect (widget, "show-object", G_CALLBACK (show_object), pl);
|
||||
|
||||
g_free (value);
|
||||
g_free (type);
|
||||
g_free (attribute);
|
||||
g_value_unset (&gvalue);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup_object (GtkInspectorPropList *pl)
|
||||
{
|
||||
@@ -583,7 +578,10 @@ gtk_inspector_prop_list_set_object (GtkInspectorPropList *pl,
|
||||
GParamSpec **props;
|
||||
guint num_properties;
|
||||
guint i;
|
||||
GtkWidget *w;
|
||||
GListStore *store;
|
||||
GListModel *list;
|
||||
GListModel *filtered;
|
||||
GtkSortListModel *sorted;
|
||||
|
||||
if (!object)
|
||||
return FALSE;
|
||||
@@ -600,19 +598,19 @@ gtk_inspector_prop_list_set_object (GtkInspectorPropList *pl,
|
||||
|
||||
pl->priv->object = object;
|
||||
|
||||
while ((w = gtk_widget_get_first_child (pl->priv->list2)))
|
||||
gtk_list_box_remove (GTK_LIST_BOX (pl->priv->list2), w);
|
||||
store = g_list_store_new (PROP_TYPE_HOLDER);
|
||||
|
||||
for (i = 0; i < num_properties; i++)
|
||||
{
|
||||
GParamSpec *prop = props[i];
|
||||
GtkWidget *row;
|
||||
PropHolder *holder;
|
||||
|
||||
if (! (prop->flags & G_PARAM_READABLE))
|
||||
continue;
|
||||
|
||||
row = gtk_inspector_prop_list_create_row (pl, prop);
|
||||
gtk_list_box_insert (GTK_LIST_BOX (pl->priv->list2), row, -1);
|
||||
holder = prop_holder_new (object, prop);
|
||||
g_list_store_append (store, holder);
|
||||
g_object_unref (holder);
|
||||
}
|
||||
|
||||
g_free (props);
|
||||
@@ -620,8 +618,21 @@ gtk_inspector_prop_list_set_object (GtkInspectorPropList *pl,
|
||||
if (GTK_IS_WIDGET (object))
|
||||
g_signal_connect_object (object, "destroy", G_CALLBACK (cleanup_object), pl, G_CONNECT_SWAPPED);
|
||||
|
||||
filtered = G_LIST_MODEL (gtk_filter_list_model_new (G_LIST_MODEL (store), pl->priv->filter));
|
||||
sorted = gtk_sort_list_model_new (filtered, NULL);
|
||||
list = G_LIST_MODEL (gtk_no_selection_new (G_LIST_MODEL (sorted)));
|
||||
|
||||
gtk_column_view_set_model (GTK_COLUMN_VIEW (pl->priv->list), list);
|
||||
gtk_sort_list_model_set_sorter (sorted, gtk_column_view_get_sorter (GTK_COLUMN_VIEW (pl->priv->list)));
|
||||
gtk_column_view_sort_by_column (GTK_COLUMN_VIEW (pl->priv->list), pl->priv->name, GTK_SORT_ASCENDING);
|
||||
|
||||
gtk_widget_show (GTK_WIDGET (pl));
|
||||
|
||||
g_object_unref (list);
|
||||
g_object_unref (sorted);
|
||||
g_object_unref (filtered);
|
||||
g_object_unref (store);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
+46
-96
@@ -8,87 +8,61 @@
|
||||
<style>
|
||||
<class name="view"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<style>
|
||||
<class name="header"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkBox" id="name_heading">
|
||||
<property name="hexpand">0</property>
|
||||
<child>
|
||||
<object class="GtkGestureClick">
|
||||
<signal name="pressed" handler="sort_changed" swapped="no"/>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Name</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="hexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage" id="name_sort_indicator">
|
||||
<style>
|
||||
<class name="sort_indicator"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="type_heading">
|
||||
<property name="label">Type</property>
|
||||
<property name="xalign">0</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="origin_heading">
|
||||
<property name="hexpand">0</property>
|
||||
<child>
|
||||
<object class="GtkGestureClick">
|
||||
<signal name="pressed" handler="sort_changed" swapped="no"/>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">Defined at</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="hexpand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage" id="origin_sort_indicator">
|
||||
<style>
|
||||
<class name="sort_indicator"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="value_heading">
|
||||
<property name="label">Value</property>
|
||||
<property name="xalign">0</property>
|
||||
<property name="hexpand">0</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="hexpand">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="list2">
|
||||
<object class="GtkColumnView" id="list">
|
||||
<style>
|
||||
<class name="list"/>
|
||||
</style>
|
||||
<property name="selection-mode">none</property>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="name">
|
||||
<property name="title" translatable="yes">Name</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_name_cb"/>
|
||||
<signal name="bind" handler="bind_name_cb"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="type">
|
||||
<property name="title" translatable="yes">Type</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_type_cb"/>
|
||||
<signal name="bind" handler="bind_type_cb"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="origin">
|
||||
<property name="title" translatable="yes">Defined At</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_origin_cb"/>
|
||||
<signal name="bind" handler="bind_origin_cb"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Value</property>
|
||||
<property name="expand">1</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="bind" handler="bind_value_cb"/>
|
||||
<signal name="unbind" handler="unbind_value_cb"/>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
@@ -96,28 +70,4 @@
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
<object class="GtkSizeGroup" id="names">
|
||||
<property name="mode">horizontal</property>
|
||||
<widgets>
|
||||
<widget name="name_heading"/>
|
||||
</widgets>
|
||||
</object>
|
||||
<object class="GtkSizeGroup" id="types">
|
||||
<property name="mode">horizontal</property>
|
||||
<widgets>
|
||||
<widget name="type_heading"/>
|
||||
</widgets>
|
||||
</object>
|
||||
<object class="GtkSizeGroup" id="origins">
|
||||
<property name="mode">horizontal</property>
|
||||
<widgets>
|
||||
<widget name="origin_heading"/>
|
||||
</widgets>
|
||||
</object>
|
||||
<object class="GtkSizeGroup" id="values">
|
||||
<property name="mode">horizontal</property>
|
||||
<widgets>
|
||||
<widget name="value_heading"/>
|
||||
</widgets>
|
||||
</object>
|
||||
</interface>
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "resource-holder.h"
|
||||
|
||||
struct _ResourceHolder {
|
||||
GObject instance;
|
||||
|
||||
char *name;
|
||||
char *path;
|
||||
int count;
|
||||
gsize size;
|
||||
GListModel *children;
|
||||
ResourceHolder *parent;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ResourceHolder, resource_holder, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
resource_holder_init (ResourceHolder *holder)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
resource_holder_finalize (GObject *object)
|
||||
{
|
||||
ResourceHolder *holder = RESOURCE_HOLDER (object);
|
||||
|
||||
g_free (holder->name);
|
||||
g_free (holder->path);
|
||||
g_clear_object (&holder->children);
|
||||
|
||||
G_OBJECT_CLASS (resource_holder_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
resource_holder_class_init (ResourceHolderClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->finalize = resource_holder_finalize;
|
||||
}
|
||||
|
||||
ResourceHolder *
|
||||
resource_holder_new (const char *name,
|
||||
const char *path,
|
||||
int count,
|
||||
gsize size,
|
||||
GListModel *children)
|
||||
{
|
||||
ResourceHolder *holder;
|
||||
|
||||
holder = g_object_new (RESOURCE_TYPE_HOLDER, NULL);
|
||||
|
||||
holder->name = g_strdup (name);
|
||||
holder->path = g_strdup (path);
|
||||
holder->count = count;
|
||||
holder->size = size;
|
||||
g_set_object (&holder->children, children);
|
||||
|
||||
if (children)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < g_list_model_get_n_items (children); i++)
|
||||
{
|
||||
ResourceHolder *child = g_list_model_get_item (children, i);
|
||||
child->parent = holder;
|
||||
g_object_unref (child);
|
||||
}
|
||||
}
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
const char *
|
||||
resource_holder_get_name (ResourceHolder *holder)
|
||||
{
|
||||
return holder->name;
|
||||
}
|
||||
|
||||
const char *
|
||||
resource_holder_get_path (ResourceHolder *holder)
|
||||
{
|
||||
return holder->path;
|
||||
}
|
||||
|
||||
int
|
||||
resource_holder_get_count (ResourceHolder *holder)
|
||||
{
|
||||
return holder->count;
|
||||
}
|
||||
|
||||
gsize
|
||||
resource_holder_get_size (ResourceHolder *holder)
|
||||
{
|
||||
return holder->size;
|
||||
}
|
||||
|
||||
GListModel *
|
||||
resource_holder_get_children (ResourceHolder *holder)
|
||||
{
|
||||
return holder->children;
|
||||
}
|
||||
|
||||
ResourceHolder *
|
||||
resource_holder_get_parent (ResourceHolder *holder)
|
||||
{
|
||||
return holder->parent;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef __RESOURCE_HOLDER_H__
|
||||
#define __RESOURCE_HOLDER_H__
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define RESOURCE_TYPE_HOLDER (resource_holder_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (ResourceHolder, resource_holder, RESOURCE, HOLDER, GObject)
|
||||
|
||||
ResourceHolder * resource_holder_new (const char *name,
|
||||
const char *path,
|
||||
int count,
|
||||
gsize size,
|
||||
GListModel *children);
|
||||
|
||||
const char *resource_holder_get_name (ResourceHolder *holder);
|
||||
const char *resource_holder_get_path (ResourceHolder *holder);
|
||||
int resource_holder_get_count (ResourceHolder *holder);
|
||||
gsize resource_holder_get_size (ResourceHolder *holder);
|
||||
GListModel *resource_holder_get_children (ResourceHolder *holder);
|
||||
ResourceHolder *resource_holder_get_parent (ResourceHolder *holder);
|
||||
|
||||
#endif /* __RESOURCE_HOLDER_H__ */
|
||||
|
||||
+463
-299
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,9 @@
|
||||
<object class="GtkSearchEntry" id="search_entry">
|
||||
<property name="max-width-chars">40</property>
|
||||
<signal name="search-changed" handler="on_search_changed"/>
|
||||
<signal name="next-match" handler="next_match"/>
|
||||
<signal name="previous-match" handler="previous_match"/>
|
||||
<signal name="stop-search" handler="stop_search"/>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
@@ -54,56 +57,45 @@
|
||||
<property name="vexpand">1</property>
|
||||
<property name="hscrollbar-policy">never</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="tree">
|
||||
<property name="model">model</property>
|
||||
<property name="enable-search">0</property>
|
||||
<property name="enable-grid-lines">vertical</property>
|
||||
<signal name="row-activated" handler="row_activated"/>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection">
|
||||
<signal name="changed" handler="on_selection_changed"/>
|
||||
</object>
|
||||
</child>
|
||||
<object class="GtkColumnView" id="list">
|
||||
<signal name="activate" handler="on_row_activated"/>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="path_column">
|
||||
<object class="GtkColumnViewColumn" id="path">
|
||||
<property name="title" translatable="yes">Path</property>
|
||||
<property name="resizable">1</property>
|
||||
<property name="sort-column-id">0</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText">
|
||||
<property name="scale">0.8</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<property name="width-chars">10</property>
|
||||
<property name="max-width-chars">5</property>
|
||||
<property name="expand">1</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_name_cb"/>
|
||||
<signal name="bind" handler="bind_name_cb"/>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="count_column">
|
||||
<object class="GtkColumnViewColumn" id="count">
|
||||
<property name="title" translatable="yes">Count</property>
|
||||
<property name="resizable">1</property>
|
||||
<property name="sort-column-id">1</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="count_renderer">
|
||||
<property name="scale">0.8</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_count_cb"/>
|
||||
<signal name="bind" handler="bind_count_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="size_column">
|
||||
<object class="GtkColumnViewColumn" id="size">
|
||||
<property name="title" translatable="yes">Size</property>
|
||||
<property name="resizable">1</property>
|
||||
<property name="sort-column-id">2</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="size_renderer">
|
||||
<property name="scale">0.8</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_size_cb"/>
|
||||
<signal name="bind" handler="bind_size_cb"/>
|
||||
</object>
|
||||
</child>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="filler">
|
||||
<property name="expand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
@@ -45,8 +45,6 @@
|
||||
#include "gtkeditable.h"
|
||||
#include "gtkentry.h"
|
||||
|
||||
#include "fallback-c89.c"
|
||||
|
||||
#ifdef GDK_WINDOWING_X11
|
||||
#include "x11/gdkx.h"
|
||||
#endif
|
||||
|
||||
+3
-3
@@ -14,7 +14,6 @@ gtk_cargs = [
|
||||
# List of sources that do not contain public API, and should not be
|
||||
# introspected
|
||||
gtk_private_sources = files([
|
||||
'fallback-c89.c',
|
||||
'fnmatch.c',
|
||||
'tools/gdkpixbufutils.c',
|
||||
'gsettings-mapping.c',
|
||||
@@ -135,6 +134,7 @@ gtk_private_sources = files([
|
||||
'gtkscaler.c',
|
||||
'gtksearchengine.c',
|
||||
'gtksearchenginemodel.c',
|
||||
'gtkset.c',
|
||||
'gtksizerequestcache.c',
|
||||
'gtkstyleanimation.c',
|
||||
'gtkstylecascade.c',
|
||||
@@ -206,7 +206,6 @@ gtk_public_sources = files([
|
||||
'gtkconstraintguide.c',
|
||||
'gtkconstraintlayout.c',
|
||||
'gtkconstraint.c',
|
||||
'gtkcoverflow.c',
|
||||
'gtkcssprovider.c',
|
||||
'gtkcustomfilter.c',
|
||||
'gtkcustomlayout.c',
|
||||
@@ -303,6 +302,7 @@ gtk_public_sources = files([
|
||||
'gtkmodules.c',
|
||||
'gtkmountoperation.c',
|
||||
'gtkmultifilter.c',
|
||||
'gtkmultiselection.c',
|
||||
'gtkmultisorter.c',
|
||||
'gtknativedialog.c',
|
||||
'gtknomediafile.c',
|
||||
@@ -486,7 +486,6 @@ gtk_public_headers = files([
|
||||
'gtkconstraintguide.h',
|
||||
'gtkconstraintlayout.h',
|
||||
'gtkconstraint.h',
|
||||
'gtkcoverflow.h',
|
||||
'gtkcssprovider.h',
|
||||
'gtkcustomfilter.h',
|
||||
'gtkcustomlayout.h',
|
||||
@@ -577,6 +576,7 @@ gtk_public_headers = files([
|
||||
'gtkmessagedialog.h',
|
||||
'gtkmountoperation.h',
|
||||
'gtkmultifilter.h',
|
||||
'gtkmultiselection.h',
|
||||
'gtkmultisorter.h',
|
||||
'gtknative.h',
|
||||
'gtknativedialog.h',
|
||||
|
||||
@@ -191,16 +191,11 @@ check_functions = [
|
||||
'getresuid',
|
||||
'lstat',
|
||||
'mmap',
|
||||
'nearbyint',
|
||||
'posix_fallocate',
|
||||
'_lock_file',
|
||||
'flockfile',
|
||||
'mkstemp',
|
||||
'mallinfo',
|
||||
'round',
|
||||
'rint',
|
||||
'log2',
|
||||
'exp2',
|
||||
'sincos',
|
||||
'sincosf',
|
||||
]
|
||||
@@ -211,10 +206,6 @@ foreach func : check_functions
|
||||
endif
|
||||
endforeach
|
||||
|
||||
cdata.set('HAVE_DECL_ISINF', cc.has_header_symbol('math.h', 'isinf'))
|
||||
cdata.set('HAVE_DECL_ISNAN', cc.has_header_symbol('math.h', 'isnan'))
|
||||
cdata.set('HAVE_DECL_ISNANF', cc.has_header_symbol('math.h', 'isnanf'))
|
||||
|
||||
# Disable deprecation checks for all libraries we depend on on stable branches.
|
||||
# This is so newer versions of those libraries don't cause more warnings with
|
||||
# a stable GTK version.
|
||||
|
||||
+183
-176
@@ -9,8 +9,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gtk+ 2.4.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-05-28 09:12+0000\n"
|
||||
"PO-Revision-Date: 2020-05-28 13:03+0300\n"
|
||||
"POT-Creation-Date: 2020-05-31 05:35+0000\n"
|
||||
"PO-Revision-Date: 2020-05-31 09:11+0300\n"
|
||||
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
|
||||
"Language-Team: Ukrainian <kde-i18n-uk@kde.org>\n"
|
||||
"Language: uk\n"
|
||||
@@ -460,7 +460,7 @@ msgid "Whether to wrap the license text."
|
||||
msgstr "Чи переносити рядку у тексті ліцензії."
|
||||
|
||||
#: gtk/gtkaccellabel.c:135 gtk/gtkbutton.c:225 gtk/gtkexpander.c:320
|
||||
#: gtk/gtkframe.c:168 gtk/gtklabel.c:746 gtk/gtkmenubutton.c:422
|
||||
#: gtk/gtkframe.c:168 gtk/gtklabel.c:745 gtk/gtkmenubutton.c:422
|
||||
msgid "Label"
|
||||
msgstr "Позначка"
|
||||
|
||||
@@ -469,12 +469,12 @@ msgid "The text displayed next to the accelerator"
|
||||
msgstr "Текст, який буде показано поряд із акселератором"
|
||||
|
||||
#: gtk/gtkaccellabel.c:142 gtk/gtkbutton.c:232 gtk/gtkexpander.c:328
|
||||
#: gtk/gtklabel.c:767 gtk/gtkmenubutton.c:429 gtk/gtkstack.c:431
|
||||
#: gtk/gtklabel.c:766 gtk/gtkmenubutton.c:429 gtk/gtkstack.c:431
|
||||
msgid "Use underline"
|
||||
msgstr "Використовувати підкреслення"
|
||||
|
||||
#: gtk/gtkaccellabel.c:143 gtk/gtkbutton.c:233 gtk/gtkexpander.c:329
|
||||
#: gtk/gtklabel.c:768 gtk/gtkmenubutton.c:430
|
||||
#: gtk/gtklabel.c:767 gtk/gtkmenubutton.c:430
|
||||
msgid ""
|
||||
"If set, an underline in the text indicates the next character should be used "
|
||||
"for the mnemonic accelerator key"
|
||||
@@ -744,7 +744,7 @@ msgstr ""
|
||||
#: gtk/gtkdragicon.c:372 gtk/gtkexpander.c:366 gtk/gtkflowbox.c:513
|
||||
#: gtk/gtkframe.c:190 gtk/gtklistbox.c:3455 gtk/gtknotebook.c:570
|
||||
#: gtk/gtkoverlay.c:319 gtk/gtkpopover.c:1665 gtk/gtkrevealer.c:354
|
||||
#: gtk/gtkscrolledwindow.c:759 gtk/gtksearchbar.c:316 gtk/gtkstack.c:381
|
||||
#: gtk/gtkscrolledwindow.c:758 gtk/gtksearchbar.c:316 gtk/gtkstack.c:381
|
||||
#: gtk/gtkviewport.c:390 gtk/gtkwindow.c:946 gtk/gtkwindowhandle.c:546
|
||||
msgid "Child"
|
||||
msgstr "Вкладений елемент"
|
||||
@@ -752,7 +752,7 @@ msgstr "Вкладений елемент"
|
||||
#: gtk/gtkaspectframe.c:167 gtk/gtkbutton.c:254 gtk/gtkexpander.c:367
|
||||
#: gtk/gtkflowbox.c:514 gtk/gtkframe.c:191 gtk/gtklistbox.c:3456
|
||||
#: gtk/gtkoverlay.c:320 gtk/gtkpopover.c:1666 gtk/gtkrevealer.c:355
|
||||
#: gtk/gtkscrolledwindow.c:760 gtk/gtksearchbar.c:317 gtk/gtkviewport.c:391
|
||||
#: gtk/gtkscrolledwindow.c:759 gtk/gtksearchbar.c:317 gtk/gtkviewport.c:391
|
||||
#: gtk/gtkwindow.c:947 gtk/gtkwindowhandle.c:547
|
||||
msgid "The child widget"
|
||||
msgstr "Дочірній віджет"
|
||||
@@ -806,7 +806,7 @@ msgid "The pages of the assistant."
|
||||
msgstr "Сторінки помічника."
|
||||
|
||||
#: gtk/gtkbox.c:259 gtk/gtkboxlayout.c:730 gtk/gtkcellareabox.c:317
|
||||
#: gtk/gtkiconview.c:473 gtk/gtktreeviewcolumn.c:304
|
||||
#: gtk/gtkiconview.c:472 gtk/gtktreeviewcolumn.c:304
|
||||
msgid "Spacing"
|
||||
msgstr "Інтервал"
|
||||
|
||||
@@ -840,27 +840,27 @@ msgstr "Розподілити рівномірно за простором"
|
||||
msgid "Spacing between widgets"
|
||||
msgstr "Інтервал між віджетами"
|
||||
|
||||
#: gtk/gtkbuilder.c:311
|
||||
#: gtk/gtkbuilder.c:313
|
||||
msgid "Translation Domain"
|
||||
msgstr "Домен перекладу"
|
||||
|
||||
#: gtk/gtkbuilder.c:312
|
||||
#: gtk/gtkbuilder.c:314
|
||||
msgid "The translation domain used by gettext"
|
||||
msgstr "Домен перекладу, що використовується gettext"
|
||||
|
||||
#: gtk/gtkbuilder.c:323
|
||||
#: gtk/gtkbuilder.c:325
|
||||
msgid "Current object"
|
||||
msgstr "Поточний об'єкт"
|
||||
|
||||
#: gtk/gtkbuilder.c:324
|
||||
#: gtk/gtkbuilder.c:326
|
||||
msgid "The object the builder is evaluating for"
|
||||
msgstr "Об'єкт для оцінки збиральником"
|
||||
|
||||
#: gtk/gtkbuilder.c:335 gtk/gtkshortcutcontroller.c:550
|
||||
#: gtk/gtkbuilder.c:337 gtk/gtkshortcutcontroller.c:551
|
||||
msgid "Scope"
|
||||
msgstr "Область"
|
||||
|
||||
#: gtk/gtkbuilder.c:336
|
||||
#: gtk/gtkbuilder.c:338
|
||||
msgid "The scope the builder is operating in"
|
||||
msgstr "Область, у якій працює будівник"
|
||||
|
||||
@@ -871,7 +871,7 @@ msgid ""
|
||||
msgstr "Текст віджета позначки в кнопці, якщо кнопка містить віджет позначки"
|
||||
|
||||
#: gtk/gtkbutton.c:239 gtk/gtkcombobox.c:671 gtk/gtkentry.c:469
|
||||
#: gtk/gtkscrolledwindow.c:641
|
||||
#: gtk/gtkscrolledwindow.c:640
|
||||
msgid "Has Frame"
|
||||
msgstr "Має рамку"
|
||||
|
||||
@@ -1187,10 +1187,10 @@ msgstr "Встановлення тла комірки"
|
||||
msgid "Whether the cell background color is set"
|
||||
msgstr "Чи встановлено колір тла комірки"
|
||||
|
||||
#: gtk/gtkcellrenderercombo.c:136 gtk/gtkfilterlistmodel.c:416
|
||||
#: gtk/gtkcellrenderercombo.c:136 gtk/gtkfilterlistmodel.c:683
|
||||
#: gtk/gtkflattenlistmodel.c:438 gtk/gtkmaplistmodel.c:404
|
||||
#: gtk/gtkshortcutcontroller.c:538 gtk/gtkslicelistmodel.c:287
|
||||
#: gtk/gtksortlistmodel.c:338 gtk/gtktreelistmodel.c:716
|
||||
#: gtk/gtkshortcutcontroller.c:539 gtk/gtkslicelistmodel.c:287
|
||||
#: gtk/gtksortlistmodel.c:394 gtk/gtktreelistmodel.c:716
|
||||
msgid "Model"
|
||||
msgstr "Модель"
|
||||
|
||||
@@ -1377,7 +1377,7 @@ msgstr "Розмітка"
|
||||
msgid "Marked up text to render"
|
||||
msgstr "Розмітка тексту до візуалізації"
|
||||
|
||||
#: gtk/gtkcellrenderertext.c:269 gtk/gtkentry.c:890 gtk/gtklabel.c:753
|
||||
#: gtk/gtkcellrenderertext.c:269 gtk/gtkentry.c:890 gtk/gtklabel.c:752
|
||||
#: gtk/gtktext.c:894
|
||||
msgid "Attributes"
|
||||
msgstr "Атрибути"
|
||||
@@ -1536,7 +1536,7 @@ msgstr ""
|
||||
"під час відтворення тексту. Якщо ви не розумієте цей параметр, то, напевно, "
|
||||
"він вам не потрібний."
|
||||
|
||||
#: gtk/gtkcellrenderertext.c:446 gtk/gtklabel.c:873 gtk/gtkprogressbar.c:246
|
||||
#: gtk/gtkcellrenderertext.c:446 gtk/gtklabel.c:872 gtk/gtkprogressbar.c:246
|
||||
msgid "Ellipsize"
|
||||
msgstr "Овал"
|
||||
|
||||
@@ -1549,15 +1549,15 @@ msgstr ""
|
||||
"для показу всього рядка"
|
||||
|
||||
#: gtk/gtkcellrenderertext.c:463 gtk/gtkfilechooserbutton.c:524
|
||||
#: gtk/gtklabel.c:891
|
||||
#: gtk/gtklabel.c:890
|
||||
msgid "Width In Characters"
|
||||
msgstr "Ширина у символах"
|
||||
|
||||
#: gtk/gtkcellrenderertext.c:464 gtk/gtklabel.c:892
|
||||
#: gtk/gtkcellrenderertext.c:464 gtk/gtklabel.c:891
|
||||
msgid "The desired width of the label, in characters"
|
||||
msgstr "Бажана ширина, у символах"
|
||||
|
||||
#: gtk/gtkcellrenderertext.c:483 gtk/gtklabel.c:925
|
||||
#: gtk/gtkcellrenderertext.c:483 gtk/gtklabel.c:924
|
||||
msgid "Maximum Width In Characters"
|
||||
msgstr "Максимальна ширина в символах"
|
||||
|
||||
@@ -1772,12 +1772,12 @@ msgstr "Модель CellView"
|
||||
msgid "The model for cell view"
|
||||
msgstr "Модель для перегляду комірки"
|
||||
|
||||
#: gtk/gtkcellview.c:215 gtk/gtkentrycompletion.c:439 gtk/gtkiconview.c:584
|
||||
#: gtk/gtkcellview.c:215 gtk/gtkentrycompletion.c:439 gtk/gtkiconview.c:583
|
||||
#: gtk/gtktreepopover.c:213 gtk/gtktreeviewcolumn.c:423
|
||||
msgid "Cell Area"
|
||||
msgstr "Ділянка комірки"
|
||||
|
||||
#: gtk/gtkcellview.c:216 gtk/gtkentrycompletion.c:440 gtk/gtkiconview.c:585
|
||||
#: gtk/gtkcellview.c:216 gtk/gtkentrycompletion.c:440 gtk/gtkiconview.c:584
|
||||
#: gtk/gtktreepopover.c:214 gtk/gtktreeviewcolumn.c:424
|
||||
msgid "The GtkCellArea used to layout cells"
|
||||
msgstr "GtkCellArea для компонування комірок"
|
||||
@@ -1891,7 +1891,7 @@ msgstr "Колір RGBA"
|
||||
msgid "Color as RGBA"
|
||||
msgstr "Колір як RGBA"
|
||||
|
||||
#: gtk/gtkcolorswatch.c:485 gtk/gtklabel.c:836 gtk/gtklistbox.c:3448
|
||||
#: gtk/gtkcolorswatch.c:485 gtk/gtklabel.c:835 gtk/gtklistbox.c:3448
|
||||
msgid "Selectable"
|
||||
msgstr "Вибирається"
|
||||
|
||||
@@ -2283,11 +2283,11 @@ msgstr "Максимальна ширина у символах"
|
||||
msgid "The desired maximum width of the entry, in characters"
|
||||
msgstr "Бажана максимальна ширина поля введення, у символах"
|
||||
|
||||
#: gtk/gtkeditable.c:423 gtk/gtklabel.c:790
|
||||
#: gtk/gtkeditable.c:423 gtk/gtklabel.c:789
|
||||
msgid "X align"
|
||||
msgstr "Вирівнювання за X"
|
||||
|
||||
#: gtk/gtkeditable.c:424 gtk/gtklabel.c:791
|
||||
#: gtk/gtkeditable.c:424 gtk/gtklabel.c:790
|
||||
msgid ""
|
||||
"The horizontal alignment, from 0 (left) to 1 (right). Reversed for RTL "
|
||||
"layouts."
|
||||
@@ -2603,7 +2603,7 @@ msgstr "Піктограма емодзі"
|
||||
msgid "Whether to show an icon for Emoji"
|
||||
msgstr "Чи слід показувати піктограму емодзі"
|
||||
|
||||
#: gtk/gtkentry.c:928 gtk/gtklabel.c:955 gtk/gtkpasswordentry.c:418
|
||||
#: gtk/gtkentry.c:928 gtk/gtklabel.c:954 gtk/gtkpasswordentry.c:418
|
||||
#: gtk/gtktext.c:940 gtk/gtktextview.c:1078
|
||||
msgid "Extra menu"
|
||||
msgstr "Додаткове меню"
|
||||
@@ -2636,7 +2636,7 @@ msgstr "Мінімальна довжина ключа"
|
||||
msgid "Minimum length of the search key in order to look up matches"
|
||||
msgstr "Мінімальна довжина ключа, при пошуку відповідностей"
|
||||
|
||||
#: gtk/gtkentrycompletion.c:354 gtk/gtkiconview.c:402
|
||||
#: gtk/gtkentrycompletion.c:354 gtk/gtkiconview.c:401
|
||||
msgid "Text column"
|
||||
msgstr "Текстовий стовпчик"
|
||||
|
||||
@@ -2741,11 +2741,11 @@ msgstr "Чи розширювач був відкритий для показу
|
||||
msgid "Text of the expander’s label"
|
||||
msgstr "Текст мітки розгортання"
|
||||
|
||||
#: gtk/gtkexpander.c:336 gtk/gtklabel.c:760 gtk/gtkmodelbutton.c:1149
|
||||
#: gtk/gtkexpander.c:336 gtk/gtklabel.c:759 gtk/gtkmodelbutton.c:1149
|
||||
msgid "Use markup"
|
||||
msgstr "Використовувати розмітку"
|
||||
|
||||
#: gtk/gtkexpander.c:337 gtk/gtklabel.c:761
|
||||
#: gtk/gtkexpander.c:337 gtk/gtklabel.c:760
|
||||
msgid "The text of the label includes XML markup. See pango_parse_markup()"
|
||||
msgstr "Текст позначки включає розмітку XML. Див. pango_parse_markup()"
|
||||
|
||||
@@ -2797,7 +2797,7 @@ msgstr "Дія"
|
||||
msgid "The type of operation that the file selector is performing"
|
||||
msgstr "Тип операції, яку виконує діалог вибору файлів"
|
||||
|
||||
#: gtk/gtkfilechooser.c:160
|
||||
#: gtk/gtkfilechooser.c:160 gtk/gtkfilterlistmodel.c:659
|
||||
msgid "Filter"
|
||||
msgstr "Фільтр"
|
||||
|
||||
@@ -2854,27 +2854,24 @@ msgstr "Підзаголовок"
|
||||
msgid "The human-readable name for this filter"
|
||||
msgstr "Зручна для читання назва цього фільтра"
|
||||
|
||||
#: gtk/gtkfilterlistmodel.c:392
|
||||
msgid "has filter"
|
||||
msgstr "має фільтр"
|
||||
#: gtk/gtkfilterlistmodel.c:660
|
||||
#| msgid "If a filter is set for this model"
|
||||
msgid "The filter set for this model"
|
||||
msgstr "Набір фільтрів для цієї моделі"
|
||||
|
||||
#: gtk/gtkfilterlistmodel.c:393
|
||||
msgid "If a filter is set for this model"
|
||||
msgstr "Чи встановлено фільтр для цієї моделі"
|
||||
|
||||
#: gtk/gtkfilterlistmodel.c:404 gtk/gtkflattenlistmodel.c:426
|
||||
#: gtk/gtkfilterlistmodel.c:671 gtk/gtkflattenlistmodel.c:426
|
||||
#: gtk/gtkmaplistmodel.c:392 gtk/gtkpropertylookuplistmodel.c:376
|
||||
#: gtk/gtkslicelistmodel.c:275 gtk/gtksortlistmodel.c:326
|
||||
#: gtk/gtkslicelistmodel.c:275 gtk/gtksortlistmodel.c:382
|
||||
msgid "Item type"
|
||||
msgstr "Тип запису"
|
||||
|
||||
#: gtk/gtkfilterlistmodel.c:405 gtk/gtkflattenlistmodel.c:427
|
||||
#: gtk/gtkfilterlistmodel.c:672 gtk/gtkflattenlistmodel.c:427
|
||||
#: gtk/gtkmaplistmodel.c:393 gtk/gtkpropertylookuplistmodel.c:377
|
||||
#: gtk/gtkslicelistmodel.c:276
|
||||
msgid "The type of elements of this object"
|
||||
msgstr "Тип елементів цього об'єкта"
|
||||
|
||||
#: gtk/gtkfilterlistmodel.c:417
|
||||
#: gtk/gtkfilterlistmodel.c:684
|
||||
msgid "The model being filtered"
|
||||
msgstr "Модель, яка фільтрується"
|
||||
|
||||
@@ -2890,22 +2887,22 @@ msgstr "Перетворення дочірнього об'єкта із фік
|
||||
msgid "The model being flattened"
|
||||
msgstr "Модель, яка сплощується"
|
||||
|
||||
#: gtk/gtkflowbox.c:3578 gtk/gtkiconview.c:369 gtk/gtklistbox.c:488
|
||||
#: gtk/gtkflowbox.c:3578 gtk/gtkiconview.c:368 gtk/gtklistbox.c:488
|
||||
#: gtk/gtktreeselection.c:140
|
||||
msgid "Selection mode"
|
||||
msgstr "Режим виділення"
|
||||
|
||||
#: gtk/gtkflowbox.c:3579 gtk/gtkiconview.c:370 gtk/gtklistbox.c:489
|
||||
#: gtk/gtkflowbox.c:3579 gtk/gtkiconview.c:369 gtk/gtklistbox.c:489
|
||||
msgid "The selection mode"
|
||||
msgstr "Режим виділення"
|
||||
|
||||
#: gtk/gtkflowbox.c:3592 gtk/gtkiconview.c:598 gtk/gtklistbox.c:496
|
||||
#: gtk/gtktreeview.c:1205
|
||||
#: gtk/gtkflowbox.c:3592 gtk/gtkiconview.c:597 gtk/gtklistbox.c:496
|
||||
#: gtk/gtktreeview.c:1203
|
||||
msgid "Activate on Single Click"
|
||||
msgstr "Активувати одиночним клацанням"
|
||||
|
||||
#: gtk/gtkflowbox.c:3593 gtk/gtkiconview.c:599 gtk/gtklistbox.c:497
|
||||
#: gtk/gtktreeview.c:1206
|
||||
#: gtk/gtkflowbox.c:3593 gtk/gtkiconview.c:598 gtk/gtklistbox.c:497
|
||||
#: gtk/gtktreeview.c:1204
|
||||
msgid "Activate row on a single click"
|
||||
msgstr "Активувати рядок одиночним клацанням"
|
||||
|
||||
@@ -3017,11 +3014,11 @@ msgstr "Параметри шрифту у форматі рядка"
|
||||
msgid "Language for which features have been selected"
|
||||
msgstr "Мова, для якої були вибрані параметри"
|
||||
|
||||
#: gtk/gtkfontchooserwidget.c:740
|
||||
#: gtk/gtkfontchooserwidget.c:664
|
||||
msgid "The tweak action"
|
||||
msgstr "Дія коригування"
|
||||
|
||||
#: gtk/gtkfontchooserwidget.c:741
|
||||
#: gtk/gtkfontchooserwidget.c:665
|
||||
msgid "The toggle action to switch to the tweak page"
|
||||
msgstr "Увімкнути дію для перемикання сторінки коригування"
|
||||
|
||||
@@ -3252,7 +3249,6 @@ msgid "Icon name"
|
||||
msgstr "Назва піктограми"
|
||||
|
||||
#: gtk/gtkicontheme.c:3588
|
||||
#| msgid "The icon name choosen during lookup"
|
||||
msgid "The icon name chosen during lookup"
|
||||
msgstr "Назва піктограми, яку вибрано під час пошуку"
|
||||
|
||||
@@ -3264,112 +3260,112 @@ msgstr "Є символічною"
|
||||
msgid "If the icon is symbolic"
|
||||
msgstr "Чи є піктограма символічною"
|
||||
|
||||
#: gtk/gtkiconview.c:386
|
||||
#: gtk/gtkiconview.c:385
|
||||
msgid "Pixbuf column"
|
||||
msgstr "Стовпчик pixbuf"
|
||||
|
||||
#: gtk/gtkiconview.c:387
|
||||
#: gtk/gtkiconview.c:386
|
||||
msgid "Model column used to retrieve the icon pixbuf from"
|
||||
msgstr ""
|
||||
"Модель стовпця, що використовується для отримання зображення (pixbuf) значка"
|
||||
|
||||
#: gtk/gtkiconview.c:403
|
||||
#: gtk/gtkiconview.c:402
|
||||
msgid "Model column used to retrieve the text from"
|
||||
msgstr "Модель стовпчика, що використовується для отримання з неї тексту"
|
||||
|
||||
#: gtk/gtkiconview.c:420
|
||||
#: gtk/gtkiconview.c:419
|
||||
msgid "Markup column"
|
||||
msgstr "Розмітка стовпчика"
|
||||
|
||||
#: gtk/gtkiconview.c:421
|
||||
#: gtk/gtkiconview.c:420
|
||||
msgid "Model column used to retrieve the text if using Pango markup"
|
||||
msgstr ""
|
||||
"Модель стовпчика, що використовується для тримання з неї тексту, якщо "
|
||||
"використовується розмітка pango"
|
||||
|
||||
#: gtk/gtkiconview.c:428
|
||||
#: gtk/gtkiconview.c:427
|
||||
msgid "Icon View Model"
|
||||
msgstr "Модель Icon View"
|
||||
|
||||
#: gtk/gtkiconview.c:429
|
||||
#: gtk/gtkiconview.c:428
|
||||
msgid "The model for the icon view"
|
||||
msgstr "Модель для перегляду у вигляді значків"
|
||||
|
||||
#: gtk/gtkiconview.c:443
|
||||
#: gtk/gtkiconview.c:442
|
||||
msgid "Number of columns"
|
||||
msgstr "Кількість стовпчиків"
|
||||
|
||||
#: gtk/gtkiconview.c:444
|
||||
#: gtk/gtkiconview.c:443
|
||||
msgid "Number of columns to display"
|
||||
msgstr "Кількість стовпчиків, які показуються"
|
||||
|
||||
#: gtk/gtkiconview.c:459
|
||||
#: gtk/gtkiconview.c:458
|
||||
msgid "Width for each item"
|
||||
msgstr "Віджет для кожного елемента"
|
||||
|
||||
#: gtk/gtkiconview.c:460
|
||||
#: gtk/gtkiconview.c:459
|
||||
msgid "The width used for each item"
|
||||
msgstr "Ширина, що використовується для кожного елемента"
|
||||
|
||||
#: gtk/gtkiconview.c:474
|
||||
#: gtk/gtkiconview.c:473
|
||||
msgid "Space which is inserted between cells of an item"
|
||||
msgstr "Простір, що вставляється між комірками елемента"
|
||||
|
||||
#: gtk/gtkiconview.c:487
|
||||
#: gtk/gtkiconview.c:486
|
||||
msgid "Row Spacing"
|
||||
msgstr "Міжрядковий інтервал"
|
||||
|
||||
#: gtk/gtkiconview.c:488
|
||||
#: gtk/gtkiconview.c:487
|
||||
msgid "Space which is inserted between grid rows"
|
||||
msgstr "Простір, що вставляється між рядками сітки"
|
||||
|
||||
#: gtk/gtkiconview.c:501
|
||||
#: gtk/gtkiconview.c:500
|
||||
msgid "Column Spacing"
|
||||
msgstr "Інтервал між стовпчиками"
|
||||
|
||||
#: gtk/gtkiconview.c:502
|
||||
#: gtk/gtkiconview.c:501
|
||||
msgid "Space which is inserted between grid columns"
|
||||
msgstr "Простір, що вставляється між стовпчиками сітки"
|
||||
|
||||
#: gtk/gtkiconview.c:515
|
||||
#: gtk/gtkiconview.c:514
|
||||
msgid "Margin"
|
||||
msgstr "Відступ"
|
||||
|
||||
#: gtk/gtkiconview.c:516
|
||||
#: gtk/gtkiconview.c:515
|
||||
msgid "Space which is inserted at the edges of the icon view"
|
||||
msgstr "Простір, що вставляється на краях перегляду піктограми"
|
||||
|
||||
#: gtk/gtkiconview.c:529
|
||||
#: gtk/gtkiconview.c:528
|
||||
msgid "Item Orientation"
|
||||
msgstr "Орієнтація пункту "
|
||||
|
||||
#: gtk/gtkiconview.c:530
|
||||
#: gtk/gtkiconview.c:529
|
||||
msgid ""
|
||||
"How the text and icon of each item are positioned relative to each other"
|
||||
msgstr ""
|
||||
"Як текст та значки кожного елемента розташовуються один відносно іншого"
|
||||
|
||||
#: gtk/gtkiconview.c:544 gtk/gtktreeview.c:1071 gtk/gtktreeviewcolumn.c:379
|
||||
#: gtk/gtkiconview.c:543 gtk/gtktreeview.c:1069 gtk/gtktreeviewcolumn.c:379
|
||||
msgid "Reorderable"
|
||||
msgstr "Дозволено перестановку"
|
||||
|
||||
#: gtk/gtkiconview.c:545 gtk/gtktreeview.c:1072
|
||||
#: gtk/gtkiconview.c:544 gtk/gtktreeview.c:1070
|
||||
msgid "View is reorderable"
|
||||
msgstr "Перегляд можна перегрупувати"
|
||||
|
||||
#: gtk/gtkiconview.c:552 gtk/gtktreeview.c:1191
|
||||
#: gtk/gtkiconview.c:551 gtk/gtktreeview.c:1189
|
||||
msgid "Tooltip Column"
|
||||
msgstr "Стовпчик підказки"
|
||||
|
||||
#: gtk/gtkiconview.c:553
|
||||
#: gtk/gtkiconview.c:552
|
||||
msgid "The column in the model containing the tooltip texts for the items"
|
||||
msgstr "Стовпчик у моделі, що містить текстову підказку для елементів"
|
||||
|
||||
#: gtk/gtkiconview.c:568
|
||||
#: gtk/gtkiconview.c:567
|
||||
msgid "Item Padding"
|
||||
msgstr "Доповнення елемента"
|
||||
|
||||
#: gtk/gtkiconview.c:569
|
||||
#: gtk/gtkiconview.c:568
|
||||
msgid "Padding around icon view items"
|
||||
msgstr "Доповнення навколо значків"
|
||||
|
||||
@@ -3449,19 +3445,19 @@ msgstr "Чи потрібно додавати стандартну кнопку
|
||||
msgid "Controls whether the info bar shows its contents or not"
|
||||
msgstr "Керує тим, чи буде показано вміст інформаційної панелі"
|
||||
|
||||
#: gtk/gtklabel.c:747
|
||||
#: gtk/gtklabel.c:746
|
||||
msgid "The text of the label"
|
||||
msgstr "Текст позначки"
|
||||
|
||||
#: gtk/gtklabel.c:754
|
||||
#: gtk/gtklabel.c:753
|
||||
msgid "A list of style attributes to apply to the text of the label"
|
||||
msgstr "Список стильових ознак для застосування до тексту позначки"
|
||||
|
||||
#: gtk/gtklabel.c:774 gtk/gtktexttag.c:386 gtk/gtktextview.c:877
|
||||
#: gtk/gtklabel.c:773 gtk/gtktexttag.c:386 gtk/gtktextview.c:877
|
||||
msgid "Justification"
|
||||
msgstr "Вирівнювання"
|
||||
|
||||
#: gtk/gtklabel.c:775
|
||||
#: gtk/gtklabel.c:774
|
||||
msgid ""
|
||||
"The alignment of the lines in the text of the label relative to each other. "
|
||||
"This does NOT affect the alignment of the label within its allocation. See "
|
||||
@@ -3471,80 +3467,80 @@ msgstr ""
|
||||
"вирівнювання мітки всередині вказаного для неї місця. З цього питання див. "
|
||||
"GtkLabel::xalign"
|
||||
|
||||
#: gtk/gtklabel.c:806
|
||||
#: gtk/gtklabel.c:805
|
||||
msgid "Y align"
|
||||
msgstr "Вирівнювання за Y"
|
||||
|
||||
#: gtk/gtklabel.c:807
|
||||
#: gtk/gtklabel.c:806
|
||||
msgid "The vertical alignment, from 0 (top) to 1 (bottom)"
|
||||
msgstr "Вертикальне вирівнювання, від 0 (вгору) до 1 (вниз)"
|
||||
|
||||
#: gtk/gtklabel.c:814
|
||||
#: gtk/gtklabel.c:813
|
||||
msgid "Line wrap"
|
||||
msgstr "Перенос рядків"
|
||||
|
||||
#: gtk/gtklabel.c:815
|
||||
#: gtk/gtklabel.c:814
|
||||
msgid "If set, wrap lines if the text becomes too wide"
|
||||
msgstr "Якщо встановлено, занадто довгі рядки переносяться"
|
||||
|
||||
#: gtk/gtklabel.c:828
|
||||
#: gtk/gtklabel.c:827
|
||||
msgid "Line wrap mode"
|
||||
msgstr "Режим переносу рядків"
|
||||
|
||||
#: gtk/gtklabel.c:829
|
||||
#: gtk/gtklabel.c:828
|
||||
msgid "If wrap is set, controls how linewrapping is done"
|
||||
msgstr ""
|
||||
"Якщо встановлено перенос рядків, контролює як виконувати перенос рядків"
|
||||
|
||||
#: gtk/gtklabel.c:837
|
||||
#: gtk/gtklabel.c:836
|
||||
msgid "Whether the label text can be selected with the mouse"
|
||||
msgstr "Чи може текст позначки бути виділений використовуючи мишу"
|
||||
|
||||
#: gtk/gtklabel.c:843
|
||||
#: gtk/gtklabel.c:842
|
||||
msgid "Mnemonic key"
|
||||
msgstr "Мнемонічна клавіша"
|
||||
|
||||
#: gtk/gtklabel.c:844
|
||||
#: gtk/gtklabel.c:843
|
||||
msgid "The mnemonic accelerator key for this label"
|
||||
msgstr "Мнемонічна клавіша-прискорювач для цієї позначки"
|
||||
|
||||
#: gtk/gtklabel.c:851
|
||||
#: gtk/gtklabel.c:850
|
||||
msgid "Mnemonic widget"
|
||||
msgstr "Мнемонічний віджет"
|
||||
|
||||
#: gtk/gtklabel.c:852
|
||||
#: gtk/gtklabel.c:851
|
||||
msgid "The widget to be activated when the label’s mnemonic key is pressed"
|
||||
msgstr ""
|
||||
"Віджет, який буде активовано під час натиснення мнемонічної клавіші позначки"
|
||||
|
||||
#: gtk/gtklabel.c:874
|
||||
#: gtk/gtklabel.c:873
|
||||
msgid ""
|
||||
"The preferred place to ellipsize the string, if the label does not have "
|
||||
"enough room to display the entire string"
|
||||
msgstr ""
|
||||
"Бажане місце для овалу рядка, якщо для показу усього рядка не вистачає місця."
|
||||
|
||||
#: gtk/gtklabel.c:908
|
||||
#: gtk/gtklabel.c:907
|
||||
msgid "Single Line Mode"
|
||||
msgstr "Режим одного рядка"
|
||||
|
||||
#: gtk/gtklabel.c:909
|
||||
#: gtk/gtklabel.c:908
|
||||
msgid "Whether the label is in single line mode"
|
||||
msgstr "Чи знаходиться рядок у режимі одного рядка"
|
||||
|
||||
#: gtk/gtklabel.c:926
|
||||
#: gtk/gtklabel.c:925
|
||||
msgid "The desired maximum width of the label, in characters"
|
||||
msgstr "Бажана максимальна ширина ярлика, у символах"
|
||||
|
||||
#: gtk/gtklabel.c:941
|
||||
#: gtk/gtklabel.c:940
|
||||
msgid "Number of lines"
|
||||
msgstr "Кількість ліній"
|
||||
|
||||
#: gtk/gtklabel.c:942
|
||||
#: gtk/gtklabel.c:941
|
||||
msgid "The desired number of lines, when ellipsizing a wrapping label"
|
||||
msgstr "Число рядків при скороченні мітки з використанням трьох крапок"
|
||||
|
||||
#: gtk/gtklabel.c:956 gtk/gtktext.c:941 gtk/gtktextview.c:1079
|
||||
#: gtk/gtklabel.c:955 gtk/gtktext.c:941 gtk/gtktextview.c:1079
|
||||
msgid "Menu model to append to the context menu"
|
||||
msgstr "Модель меню для долучення до контекстного меню"
|
||||
|
||||
@@ -3819,7 +3815,7 @@ msgstr "Гучність"
|
||||
msgid "Volume of the audio stream."
|
||||
msgstr "Гучність відтворення потоку звукових даних."
|
||||
|
||||
#: gtk/gtkmenubutton.c:370 gtk/gtkpopovermenubar.c:595 gtk/gtkpopovermenu.c:518
|
||||
#: gtk/gtkmenubutton.c:370 gtk/gtkpopovermenubar.c:593 gtk/gtkpopovermenu.c:517
|
||||
msgid "Menu model"
|
||||
msgstr "Модель меню"
|
||||
|
||||
@@ -4503,19 +4499,19 @@ msgstr "Мнемоніка видима"
|
||||
msgid "Whether mnemonics are currently visible in this popover"
|
||||
msgstr "Чи показано мнемоніку у цьому накладному меню"
|
||||
|
||||
#: gtk/gtkpopovermenubar.c:596
|
||||
#: gtk/gtkpopovermenubar.c:594
|
||||
msgid "The model from which the bar is made."
|
||||
msgstr "Модель, на основі якої створено панель."
|
||||
|
||||
#: gtk/gtkpopovermenu.c:510
|
||||
#: gtk/gtkpopovermenu.c:509
|
||||
msgid "Visible submenu"
|
||||
msgstr "Видиме підменю"
|
||||
|
||||
#: gtk/gtkpopovermenu.c:511
|
||||
#: gtk/gtkpopovermenu.c:510
|
||||
msgid "The name of the visible submenu"
|
||||
msgstr "Назва видимого підменю"
|
||||
|
||||
#: gtk/gtkpopovermenu.c:519
|
||||
#: gtk/gtkpopovermenu.c:518
|
||||
msgid "The model from which the menu is made."
|
||||
msgstr "Модель, для якої створено меню."
|
||||
|
||||
@@ -5054,105 +5050,105 @@ msgstr "Політика вертикальної прокрутки"
|
||||
msgid "The GtkAdjustment that contains the current value of this scrollbar"
|
||||
msgstr "Об'єкт GtkAdjustment, що містить поточне значення цієї смужки гортання"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:603
|
||||
#: gtk/gtkscrolledwindow.c:602
|
||||
msgid "Horizontal Adjustment"
|
||||
msgstr "Горизонтальне вирівнювання"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:604
|
||||
#: gtk/gtkscrolledwindow.c:603
|
||||
msgid "The GtkAdjustment for the horizontal position"
|
||||
msgstr "Об'єкт GtkAdjustment для горизонтальної позиції"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:610
|
||||
#: gtk/gtkscrolledwindow.c:609
|
||||
msgid "Vertical Adjustment"
|
||||
msgstr "Вертикальне вирівнювання"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:611
|
||||
#: gtk/gtkscrolledwindow.c:610
|
||||
msgid "The GtkAdjustment for the vertical position"
|
||||
msgstr "Об'єкт GtkAdjustment для вертикальної позиції"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:617
|
||||
#: gtk/gtkscrolledwindow.c:616
|
||||
msgid "Horizontal Scrollbar Policy"
|
||||
msgstr "Правило горизонтальної прокрутки"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:618
|
||||
#: gtk/gtkscrolledwindow.c:617
|
||||
msgid "When the horizontal scrollbar is displayed"
|
||||
msgstr "Коли показано горизонтальну панель прокрутки"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:625
|
||||
#: gtk/gtkscrolledwindow.c:624
|
||||
msgid "Vertical Scrollbar Policy"
|
||||
msgstr "Правило вертикальної прокрутки"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:626
|
||||
#: gtk/gtkscrolledwindow.c:625
|
||||
msgid "When the vertical scrollbar is displayed"
|
||||
msgstr "Коли показано вертикальну панель прокрутки"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:633
|
||||
#: gtk/gtkscrolledwindow.c:632
|
||||
msgid "Window Placement"
|
||||
msgstr "Розміщення вікна"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:634
|
||||
#: gtk/gtkscrolledwindow.c:633
|
||||
msgid "Where the contents are located with respect to the scrollbars."
|
||||
msgstr "Чи розташовувати вміст у відповідності зі смугами гортання."
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:642
|
||||
#: gtk/gtkscrolledwindow.c:641
|
||||
msgid "Whether to draw a frame around the contents"
|
||||
msgstr "Чи слід малювати рамку навколо вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:653
|
||||
#: gtk/gtkscrolledwindow.c:652
|
||||
msgid "Minimum Content Width"
|
||||
msgstr "Мінімальна ширина вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:654
|
||||
#: gtk/gtkscrolledwindow.c:653
|
||||
msgid "The minimum width that the scrolled window will allocate to its content"
|
||||
msgstr "Мінімальна ширина, яку вікна прокрутки виділять з його вмістом"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:665
|
||||
#: gtk/gtkscrolledwindow.c:664
|
||||
msgid "Minimum Content Height"
|
||||
msgstr "Мінімальна висота вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:666
|
||||
#: gtk/gtkscrolledwindow.c:665
|
||||
msgid ""
|
||||
"The minimum height that the scrolled window will allocate to its content"
|
||||
msgstr "Мінімальна висота, яку вікна прокрутки виділять з його вмістом"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:678
|
||||
#: gtk/gtkscrolledwindow.c:677
|
||||
msgid "Kinetic Scrolling"
|
||||
msgstr "Кінетичне прокручування"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:679
|
||||
#: gtk/gtkscrolledwindow.c:678
|
||||
msgid "Kinetic scrolling mode."
|
||||
msgstr "Режим кінетичного прокручування."
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:696
|
||||
#: gtk/gtkscrolledwindow.c:695
|
||||
msgid "Overlay Scrolling"
|
||||
msgstr "Накладні смуги гортання"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:697
|
||||
#: gtk/gtkscrolledwindow.c:696
|
||||
msgid "Overlay scrolling mode"
|
||||
msgstr "Режим накладних смуг гортання"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:708
|
||||
#: gtk/gtkscrolledwindow.c:707
|
||||
msgid "Maximum Content Width"
|
||||
msgstr "Максимальна ширина вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:709
|
||||
#: gtk/gtkscrolledwindow.c:708
|
||||
msgid "The maximum width that the scrolled window will allocate to its content"
|
||||
msgstr "Максимальна ширина, яку вікна зі смужками гортання матимуть для вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:720
|
||||
#: gtk/gtkscrolledwindow.c:719
|
||||
msgid "Maximum Content Height"
|
||||
msgstr "Максимальна висота вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:721
|
||||
#: gtk/gtkscrolledwindow.c:720
|
||||
msgid ""
|
||||
"The maximum height that the scrolled window will allocate to its content"
|
||||
msgstr "Максимальна висота, яку вікна зі смужками гортання матимуть для вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:736 gtk/gtkscrolledwindow.c:737
|
||||
#: gtk/gtkscrolledwindow.c:735 gtk/gtkscrolledwindow.c:736
|
||||
msgid "Propagate Natural Width"
|
||||
msgstr "Передавати природну ширину"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:752 gtk/gtkscrolledwindow.c:753
|
||||
#: gtk/gtkscrolledwindow.c:751 gtk/gtkscrolledwindow.c:752
|
||||
msgid "Propagate Natural Height"
|
||||
msgstr "Передавати природну висоту"
|
||||
|
||||
@@ -5591,19 +5587,19 @@ msgstr "Чи показувати курсор у тексті"
|
||||
msgid "Whether to use overlay scrollbars"
|
||||
msgstr "Чи використовувати накладання смужок гортання"
|
||||
|
||||
#: gtk/gtkshortcutaction.c:935
|
||||
#: gtk/gtkshortcutaction.c:942
|
||||
msgid "Signal Name"
|
||||
msgstr "Назва сигналу"
|
||||
|
||||
#: gtk/gtkshortcutaction.c:936
|
||||
#: gtk/gtkshortcutaction.c:943
|
||||
msgid "The name of the signal to emit"
|
||||
msgstr "Назва сигналу, який слід надіслати"
|
||||
|
||||
#: gtk/gtkshortcutaction.c:1174 gtk/gtkshortcutsshortcut.c:718
|
||||
#: gtk/gtkshortcutaction.c:1181 gtk/gtkshortcutsshortcut.c:718
|
||||
msgid "Action Name"
|
||||
msgstr "Назва дії"
|
||||
|
||||
#: gtk/gtkshortcutaction.c:1175
|
||||
#: gtk/gtkshortcutaction.c:1182
|
||||
msgid "The name of the action to activate"
|
||||
msgstr "Назва дії для активації"
|
||||
|
||||
@@ -5627,21 +5623,21 @@ msgstr "Перемикач"
|
||||
msgid "The trigger for this shortcut"
|
||||
msgstr "Перемикач для цього скорочення"
|
||||
|
||||
#: gtk/gtkshortcutcontroller.c:525
|
||||
#: gtk/gtkshortcutcontroller.c:526
|
||||
msgid "Mnemonic modifers"
|
||||
msgstr "Модифікатори мнемоніки"
|
||||
|
||||
#: gtk/gtkshortcutcontroller.c:526
|
||||
#: gtk/gtkshortcutcontroller.c:527
|
||||
msgid "The modifiers to be pressed to allow mnemonics activation"
|
||||
msgstr ""
|
||||
"Клавіші-модифікатори, які має бути натиснуто, щоб уможливити активацію "
|
||||
"мнемоніки"
|
||||
|
||||
#: gtk/gtkshortcutcontroller.c:539
|
||||
#: gtk/gtkshortcutcontroller.c:540
|
||||
msgid "A list model to take shortcuts from"
|
||||
msgstr "Модель списку, з якої слід брати скорочення"
|
||||
|
||||
#: gtk/gtkshortcutcontroller.c:551
|
||||
#: gtk/gtkshortcutcontroller.c:552
|
||||
msgid "What scope the shortcuts will be handled in"
|
||||
msgstr "Область, у якій оброблятимуться скорочення"
|
||||
|
||||
@@ -5823,19 +5819,21 @@ msgstr "Зсув зрізу"
|
||||
msgid "Maximum size of slice"
|
||||
msgstr "Максимальний розмір зрізу"
|
||||
|
||||
#: gtk/gtksortlistmodel.c:314
|
||||
msgid "has sort"
|
||||
msgstr "має упорядкування"
|
||||
#: gtk/gtksortlistmodel.c:370
|
||||
#| msgid "Sort order"
|
||||
msgid "Sorter"
|
||||
msgstr "Сортувальник"
|
||||
|
||||
#: gtk/gtksortlistmodel.c:315
|
||||
msgid "If a sort function is set for this model"
|
||||
msgstr "Чи встановлено функцію упорядкування для цієї моделі"
|
||||
#: gtk/gtksortlistmodel.c:371
|
||||
#| msgid "The trigger for this shortcut"
|
||||
msgid "The sorter for this model"
|
||||
msgstr "Сортувальник для цієї моделі"
|
||||
|
||||
#: gtk/gtksortlistmodel.c:327
|
||||
#: gtk/gtksortlistmodel.c:383
|
||||
msgid "The type of items of this list"
|
||||
msgstr "Тип пунктів у цьому списку"
|
||||
|
||||
#: gtk/gtksortlistmodel.c:339
|
||||
#: gtk/gtksortlistmodel.c:395
|
||||
msgid "The model being sorted"
|
||||
msgstr "Модель, яка зберігається"
|
||||
|
||||
@@ -6750,126 +6748,126 @@ msgstr "модель"
|
||||
msgid "The model for the popover"
|
||||
msgstr "Модель для накладного меню"
|
||||
|
||||
#: gtk/gtktreeview.c:1043
|
||||
#: gtk/gtktreeview.c:1041
|
||||
msgid "TreeView Model"
|
||||
msgstr "Модель TreeView"
|
||||
|
||||
#: gtk/gtktreeview.c:1044
|
||||
#: gtk/gtktreeview.c:1042
|
||||
msgid "The model for the tree view"
|
||||
msgstr "Модель для перегляду у вигляді дерева"
|
||||
|
||||
#: gtk/gtktreeview.c:1050
|
||||
#: gtk/gtktreeview.c:1048
|
||||
msgid "Headers Visible"
|
||||
msgstr "Заголовки видимі"
|
||||
|
||||
#: gtk/gtktreeview.c:1051
|
||||
#: gtk/gtktreeview.c:1049
|
||||
msgid "Show the column header buttons"
|
||||
msgstr "Показувати кнопки заголовків стовпчиків"
|
||||
|
||||
#: gtk/gtktreeview.c:1057
|
||||
#: gtk/gtktreeview.c:1055
|
||||
msgid "Headers Clickable"
|
||||
msgstr "Заголовки натискаються"
|
||||
|
||||
#: gtk/gtktreeview.c:1058
|
||||
#: gtk/gtktreeview.c:1056
|
||||
msgid "Column headers respond to click events"
|
||||
msgstr "Заголовки стовпчиків відповідають на події клацання"
|
||||
|
||||
#: gtk/gtktreeview.c:1064
|
||||
#: gtk/gtktreeview.c:1062
|
||||
msgid "Expander Column"
|
||||
msgstr "Колонка-розширювач"
|
||||
|
||||
#: gtk/gtktreeview.c:1065
|
||||
#: gtk/gtktreeview.c:1063
|
||||
msgid "Set the column for the expander column"
|
||||
msgstr "Встановити колонку для розширювача"
|
||||
|
||||
#: gtk/gtktreeview.c:1078
|
||||
#: gtk/gtktreeview.c:1076
|
||||
msgid "Enable Search"
|
||||
msgstr "Дозволено пошук"
|
||||
|
||||
#: gtk/gtktreeview.c:1079
|
||||
#: gtk/gtktreeview.c:1077
|
||||
msgid "View allows user to search through columns interactively"
|
||||
msgstr ""
|
||||
"Перегляд дозволяє користувачу виконувати пошук у стовпчиках в інтерактивному "
|
||||
"режимі"
|
||||
|
||||
#: gtk/gtktreeview.c:1085
|
||||
#: gtk/gtktreeview.c:1083
|
||||
msgid "Search Column"
|
||||
msgstr "Стовпчик пошуку"
|
||||
|
||||
#: gtk/gtktreeview.c:1086
|
||||
#: gtk/gtktreeview.c:1084
|
||||
msgid "Model column to search through during interactive search"
|
||||
msgstr ""
|
||||
"Стовпчик моделі, за яким слід виконати інтерактивний пошук в міру набору"
|
||||
|
||||
#: gtk/gtktreeview.c:1102
|
||||
#: gtk/gtktreeview.c:1100
|
||||
msgid "Fixed Height Mode"
|
||||
msgstr "Режим фіксованої висоти"
|
||||
|
||||
#: gtk/gtktreeview.c:1103
|
||||
#: gtk/gtktreeview.c:1101
|
||||
msgid "Speeds up GtkTreeView by assuming that all rows have the same height"
|
||||
msgstr "Прискорює GtkTreeView, вважаючи що всі рядки мають ту ж саму висоту"
|
||||
|
||||
#: gtk/gtktreeview.c:1120
|
||||
#: gtk/gtktreeview.c:1118
|
||||
msgid "Hover Selection"
|
||||
msgstr "Курсорне виділення"
|
||||
|
||||
#: gtk/gtktreeview.c:1121
|
||||
#: gtk/gtktreeview.c:1119
|
||||
msgid "Whether the selection should follow the pointer"
|
||||
msgstr "Чи повинно виділення слідувати за вказівником"
|
||||
|
||||
#: gtk/gtktreeview.c:1137
|
||||
#: gtk/gtktreeview.c:1135
|
||||
msgid "Hover Expand"
|
||||
msgstr "Курсорне розширення"
|
||||
|
||||
#: gtk/gtktreeview.c:1138
|
||||
#: gtk/gtktreeview.c:1136
|
||||
msgid ""
|
||||
"Whether rows should be expanded/collapsed when the pointer moves over them"
|
||||
msgstr ""
|
||||
"Чи повинні рядки розгортатись/згортатись при переміщенні над ними вказівника"
|
||||
|
||||
#: gtk/gtktreeview.c:1149
|
||||
#: gtk/gtktreeview.c:1147
|
||||
msgid "Show Expanders"
|
||||
msgstr "Показувати розширювачі"
|
||||
|
||||
#: gtk/gtktreeview.c:1150
|
||||
#: gtk/gtktreeview.c:1148
|
||||
msgid "View has expanders"
|
||||
msgstr "Віджет містить розширювачі"
|
||||
|
||||
#: gtk/gtktreeview.c:1161
|
||||
#: gtk/gtktreeview.c:1159
|
||||
msgid "Level Indentation"
|
||||
msgstr "Вирівнювання позначок"
|
||||
|
||||
#: gtk/gtktreeview.c:1162
|
||||
#: gtk/gtktreeview.c:1160
|
||||
msgid "Extra indentation for each level"
|
||||
msgstr "Додаткове вирівнювання для кожного рівня"
|
||||
|
||||
#: gtk/gtktreeview.c:1169
|
||||
#: gtk/gtktreeview.c:1167
|
||||
msgid "Rubber Banding"
|
||||
msgstr "Гумова стрічка"
|
||||
|
||||
#: gtk/gtktreeview.c:1170
|
||||
#: gtk/gtktreeview.c:1168
|
||||
msgid ""
|
||||
"Whether to enable selection of multiple items by dragging the mouse pointer"
|
||||
msgstr ""
|
||||
"Чи дозволяти виділення кількох елементів перетягуванням вказівника миші"
|
||||
|
||||
#: gtk/gtktreeview.c:1176
|
||||
#: gtk/gtktreeview.c:1174
|
||||
msgid "Enable Grid Lines"
|
||||
msgstr "Увімкнути лінії сітки"
|
||||
|
||||
#: gtk/gtktreeview.c:1177
|
||||
#: gtk/gtktreeview.c:1175
|
||||
msgid "Whether grid lines should be drawn in the tree view"
|
||||
msgstr "Чи слід показувати лінії ґраток у віджеті"
|
||||
|
||||
#: gtk/gtktreeview.c:1184
|
||||
#: gtk/gtktreeview.c:1182
|
||||
msgid "Enable Tree Lines"
|
||||
msgstr "Увімкнути лінії рівня вкладення"
|
||||
|
||||
#: gtk/gtktreeview.c:1185
|
||||
#: gtk/gtktreeview.c:1183
|
||||
msgid "Whether tree lines should be drawn in the tree view"
|
||||
msgstr "Чи слід показувати лінії рівня вкладення у віджеті"
|
||||
|
||||
#: gtk/gtktreeview.c:1192
|
||||
#: gtk/gtktreeview.c:1190
|
||||
msgid "The column in the model containing the tooltip texts for the rows"
|
||||
msgstr ""
|
||||
"Стовпчик у моделі джерела даних, що містить текстові підказки для рядків"
|
||||
@@ -7466,6 +7464,15 @@ msgstr "Назва профілю кольору"
|
||||
msgid "The title of the color profile to use"
|
||||
msgstr "Заголовок вікна вибору профілю кольору"
|
||||
|
||||
#~ msgid "has filter"
|
||||
#~ msgstr "має фільтр"
|
||||
|
||||
#~ msgid "has sort"
|
||||
#~ msgstr "має упорядкування"
|
||||
|
||||
#~ msgid "If a sort function is set for this model"
|
||||
#~ msgstr "Чи встановлено функцію упорядкування для цієї моделі"
|
||||
|
||||
#~ msgid "Application menu"
|
||||
#~ msgstr "Меню програм"
|
||||
|
||||
|
||||
+262
-36
@@ -15,23 +15,13 @@
|
||||
*/
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static int win_activated;
|
||||
static int box_activated;
|
||||
|
||||
static void
|
||||
win_activate (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
activate (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
win_activated++;
|
||||
}
|
||||
|
||||
static void
|
||||
box_activate (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
box_activated++;
|
||||
int *activated = user_data;
|
||||
(*activated)++;
|
||||
}
|
||||
|
||||
/* Test that inheriting actions along the widget
|
||||
@@ -40,20 +30,31 @@ box_activate (GSimpleAction *action,
|
||||
* the effect of activating them.
|
||||
*/
|
||||
static void
|
||||
test_action (void)
|
||||
test_inheritance (void)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *box;
|
||||
GtkWidget *button;
|
||||
GSimpleActionGroup *win_actions;
|
||||
GSimpleActionGroup *box_actions;
|
||||
GActionEntry win_entries[] = {
|
||||
{ "action", win_activate, NULL, NULL, NULL },
|
||||
};
|
||||
GActionEntry box_entries[] = {
|
||||
{ "action", box_activate, NULL, NULL, NULL },
|
||||
GActionEntry entries[] = {
|
||||
{ "action", activate, NULL, NULL, NULL },
|
||||
};
|
||||
gboolean found;
|
||||
int win_activated;
|
||||
int box_activated;
|
||||
|
||||
win_activated = 0;
|
||||
box_activated = 0;
|
||||
|
||||
/* Our hierarchy looks like this:
|
||||
*
|
||||
* window win.action
|
||||
* |
|
||||
* box box.action
|
||||
* |
|
||||
* button
|
||||
*/
|
||||
window = gtk_window_new ();
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
button = gtk_button_new ();
|
||||
@@ -63,15 +64,13 @@ test_action (void)
|
||||
|
||||
win_actions = g_simple_action_group_new ();
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win_actions),
|
||||
win_entries,
|
||||
G_N_ELEMENTS (win_entries),
|
||||
NULL);
|
||||
entries, G_N_ELEMENTS (entries),
|
||||
&win_activated);
|
||||
|
||||
box_actions = g_simple_action_group_new ();
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (box_actions),
|
||||
box_entries,
|
||||
G_N_ELEMENTS (box_entries),
|
||||
NULL);
|
||||
entries, G_N_ELEMENTS (entries),
|
||||
&box_activated);
|
||||
|
||||
gtk_widget_insert_action_group (window, "win", G_ACTION_GROUP (win_actions));
|
||||
gtk_widget_insert_action_group (box, "box", G_ACTION_GROUP (box_actions));
|
||||
@@ -79,23 +78,27 @@ test_action (void)
|
||||
g_assert_cmpint (win_activated, ==, 0);
|
||||
g_assert_cmpint (box_activated, ==, 0);
|
||||
|
||||
gtk_widget_activate_action (button, "win.action", NULL);
|
||||
found = gtk_widget_activate_action (button, "win.action", NULL);
|
||||
|
||||
g_assert_true (found);
|
||||
g_assert_cmpint (win_activated, ==, 1);
|
||||
g_assert_cmpint (box_activated, ==, 0);
|
||||
|
||||
gtk_widget_activate_action (box, "win.action", NULL);
|
||||
found = gtk_widget_activate_action (box, "win.action", NULL);
|
||||
|
||||
g_assert_true (found);
|
||||
g_assert_cmpint (win_activated, ==, 2);
|
||||
g_assert_cmpint (box_activated, ==, 0);
|
||||
|
||||
gtk_widget_activate_action (button, "box.action", NULL);
|
||||
found = gtk_widget_activate_action (button, "box.action", NULL);
|
||||
|
||||
g_assert_true (found);
|
||||
g_assert_cmpint (win_activated, ==, 2);
|
||||
g_assert_cmpint (box_activated, ==, 1);
|
||||
|
||||
gtk_widget_activate_action (window, "box.action", NULL);
|
||||
found = gtk_widget_activate_action (window, "box.action", NULL);
|
||||
|
||||
g_assert_false (found);
|
||||
g_assert_cmpint (win_activated, ==, 2);
|
||||
g_assert_cmpint (box_activated, ==, 1);
|
||||
|
||||
@@ -104,6 +107,225 @@ test_action (void)
|
||||
g_object_unref (box_actions);
|
||||
}
|
||||
|
||||
/* Test action inheritance with hierarchy changes */
|
||||
static void
|
||||
test_inheritance2 (void)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *box;
|
||||
GtkWidget *box1;
|
||||
GtkWidget *box2;
|
||||
GtkWidget *button;
|
||||
GSimpleActionGroup *win_actions;
|
||||
GSimpleActionGroup *box1_actions;
|
||||
GSimpleActionGroup *box2_actions;
|
||||
GActionEntry entries[] = {
|
||||
{ "action", activate, NULL, NULL, NULL },
|
||||
};
|
||||
gboolean found;
|
||||
int win_activated;
|
||||
int box1_activated;
|
||||
int box2_activated;
|
||||
|
||||
win_activated = 0;
|
||||
box1_activated = 0;
|
||||
box2_activated = 0;
|
||||
|
||||
/* Our hierarchy looks like this:
|
||||
*
|
||||
* window win.action
|
||||
* |
|
||||
* box--------------------+
|
||||
* | |
|
||||
* box1 box1.action box2 box2.action;
|
||||
* |
|
||||
* button
|
||||
*/
|
||||
window = gtk_window_new ();
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
box1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
button = gtk_button_new ();
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
gtk_box_append (GTK_BOX (box), box1);
|
||||
gtk_box_append (GTK_BOX (box), box2);
|
||||
gtk_box_append (GTK_BOX (box1), button);
|
||||
|
||||
win_actions = g_simple_action_group_new ();
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win_actions),
|
||||
entries, G_N_ELEMENTS (entries),
|
||||
&win_activated);
|
||||
|
||||
box1_actions = g_simple_action_group_new ();
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (box1_actions),
|
||||
entries, G_N_ELEMENTS (entries),
|
||||
&box1_activated);
|
||||
|
||||
box2_actions = g_simple_action_group_new ();
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (box2_actions),
|
||||
entries, G_N_ELEMENTS (entries),
|
||||
&box2_activated);
|
||||
|
||||
gtk_widget_insert_action_group (window, "win", G_ACTION_GROUP (win_actions));
|
||||
gtk_widget_insert_action_group (box1, "box1", G_ACTION_GROUP (box1_actions));
|
||||
gtk_widget_insert_action_group (box2, "box2", G_ACTION_GROUP (box2_actions));
|
||||
|
||||
g_assert_cmpint (win_activated, ==, 0);
|
||||
g_assert_cmpint (box1_activated, ==, 0);
|
||||
g_assert_cmpint (box2_activated, ==, 0);
|
||||
|
||||
found = gtk_widget_activate_action (button, "win.action", NULL);
|
||||
|
||||
g_assert_true (found);
|
||||
g_assert_cmpint (win_activated, ==, 1);
|
||||
g_assert_cmpint (box1_activated, ==, 0);
|
||||
g_assert_cmpint (box2_activated, ==, 0);
|
||||
|
||||
found = gtk_widget_activate_action (button, "box1.action", NULL);
|
||||
|
||||
g_assert_true (found);
|
||||
g_assert_cmpint (win_activated, ==, 1);
|
||||
g_assert_cmpint (box1_activated, ==, 1);
|
||||
g_assert_cmpint (box2_activated, ==, 0);
|
||||
|
||||
found = gtk_widget_activate_action (button, "box2.action", NULL);
|
||||
|
||||
g_assert_false (found);
|
||||
g_assert_cmpint (win_activated, ==, 1);
|
||||
g_assert_cmpint (box1_activated, ==, 1);
|
||||
g_assert_cmpint (box2_activated, ==, 0);
|
||||
|
||||
g_object_ref (button);
|
||||
gtk_box_remove (GTK_BOX (box1), button);
|
||||
gtk_box_append (GTK_BOX (box2), button);
|
||||
g_object_unref (button);
|
||||
|
||||
found = gtk_widget_activate_action (button, "win.action", NULL);
|
||||
|
||||
g_assert_true (found);
|
||||
g_assert_cmpint (win_activated, ==, 2);
|
||||
g_assert_cmpint (box1_activated, ==, 1);
|
||||
g_assert_cmpint (box2_activated, ==, 0);
|
||||
|
||||
found = gtk_widget_activate_action (button, "box1.action", NULL);
|
||||
|
||||
g_assert_false (found);
|
||||
g_assert_cmpint (win_activated, ==, 2);
|
||||
g_assert_cmpint (box1_activated, ==, 1);
|
||||
g_assert_cmpint (box2_activated, ==, 0);
|
||||
|
||||
found = gtk_widget_activate_action (button, "box2.action", NULL);
|
||||
|
||||
g_assert_true (found);
|
||||
g_assert_cmpint (win_activated, ==, 2);
|
||||
g_assert_cmpint (box1_activated, ==, 1);
|
||||
g_assert_cmpint (box2_activated, ==, 1);
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
g_object_unref (win_actions);
|
||||
g_object_unref (box1_actions);
|
||||
g_object_unref (box2_actions);
|
||||
}
|
||||
|
||||
/* Similar to test_inheritance2, but using the actionable machinery
|
||||
*/
|
||||
static void
|
||||
test_inheritance3 (void)
|
||||
{
|
||||
GtkWidget *window;
|
||||
GtkWidget *box;
|
||||
GtkWidget *box1;
|
||||
GtkWidget *box2;
|
||||
GtkWidget *button;
|
||||
GSimpleActionGroup *win_actions;
|
||||
GSimpleActionGroup *box1_actions;
|
||||
GActionEntry entries[] = {
|
||||
{ "action", activate, NULL, NULL, NULL },
|
||||
};
|
||||
int activated;
|
||||
|
||||
/* Our hierarchy looks like this:
|
||||
*
|
||||
* window win.action
|
||||
* |
|
||||
* box--------------------+
|
||||
* | |
|
||||
* box1 box1.action box2
|
||||
* |
|
||||
* button
|
||||
*/
|
||||
window = gtk_window_new ();
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
box1 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
button = gtk_button_new ();
|
||||
|
||||
gtk_window_set_child (GTK_WINDOW (window), box);
|
||||
gtk_box_append (GTK_BOX (box), box1);
|
||||
gtk_box_append (GTK_BOX (box), box2);
|
||||
gtk_box_append (GTK_BOX (box1), button);
|
||||
|
||||
win_actions = g_simple_action_group_new ();
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win_actions),
|
||||
entries, G_N_ELEMENTS (entries),
|
||||
&activated);
|
||||
|
||||
box1_actions = g_simple_action_group_new ();
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (box1_actions),
|
||||
entries, G_N_ELEMENTS (entries),
|
||||
&activated);
|
||||
|
||||
gtk_widget_insert_action_group (window, "win", G_ACTION_GROUP (win_actions));
|
||||
gtk_widget_insert_action_group (box1, "box1", G_ACTION_GROUP (box1_actions));
|
||||
|
||||
gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "box1.action");
|
||||
|
||||
g_assert_true (gtk_widget_get_sensitive (button));
|
||||
|
||||
g_object_ref (button);
|
||||
gtk_box_remove (GTK_BOX (box1), button);
|
||||
gtk_box_append (GTK_BOX (box2), button);
|
||||
g_object_unref (button);
|
||||
|
||||
g_assert_false (gtk_widget_get_sensitive (button));
|
||||
|
||||
g_object_ref (button);
|
||||
gtk_box_remove (GTK_BOX (box2), button);
|
||||
gtk_box_append (GTK_BOX (box1), button);
|
||||
g_object_unref (button);
|
||||
|
||||
g_assert_true (gtk_widget_get_sensitive (button));
|
||||
|
||||
g_object_ref (button);
|
||||
gtk_box_remove (GTK_BOX (box1), button);
|
||||
gtk_box_append (GTK_BOX (box2), button);
|
||||
g_object_unref (button);
|
||||
|
||||
g_assert_false (gtk_widget_get_sensitive (button));
|
||||
|
||||
g_object_ref (box2);
|
||||
gtk_box_remove (GTK_BOX (box), box2);
|
||||
gtk_box_append (GTK_BOX (box1), box2);
|
||||
g_object_unref (box2);
|
||||
|
||||
g_assert_true (gtk_widget_get_sensitive (button));
|
||||
|
||||
gtk_widget_insert_action_group (box1, "box1", NULL);
|
||||
|
||||
g_assert_false (gtk_widget_get_sensitive (button));
|
||||
|
||||
gtk_widget_insert_action_group (box1, "box1", G_ACTION_GROUP (box1_actions));
|
||||
|
||||
g_assert_true (gtk_widget_get_sensitive (button));
|
||||
|
||||
gtk_window_destroy (GTK_WINDOW (window));
|
||||
|
||||
g_object_unref (win_actions);
|
||||
g_object_unref (box1_actions);
|
||||
}
|
||||
|
||||
static int cut_activated;
|
||||
static int copy_activated;
|
||||
static int paste_activated;
|
||||
@@ -199,13 +421,15 @@ test_overlap (void)
|
||||
GtkWidget *window;
|
||||
GtkWidget *box;
|
||||
GActionEntry win_entries[] = {
|
||||
{ "win", win_activate, NULL, NULL, NULL },
|
||||
{ "win", activate, NULL, NULL, NULL },
|
||||
};
|
||||
GActionEntry box_entries[] = {
|
||||
{ "box", box_activate, NULL, NULL, NULL },
|
||||
{ "box", activate, NULL, NULL, NULL },
|
||||
};
|
||||
GSimpleActionGroup *win_actions;
|
||||
GSimpleActionGroup *box_actions;
|
||||
int win_activated;
|
||||
int box_activated;
|
||||
|
||||
window = gtk_window_new ();
|
||||
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||||
@@ -216,13 +440,13 @@ test_overlap (void)
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (win_actions),
|
||||
win_entries,
|
||||
G_N_ELEMENTS (win_entries),
|
||||
NULL);
|
||||
&win_activated);
|
||||
|
||||
box_actions = g_simple_action_group_new ();
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (box_actions),
|
||||
box_entries,
|
||||
G_N_ELEMENTS (box_entries),
|
||||
NULL);
|
||||
&box_activated);
|
||||
|
||||
gtk_widget_insert_action_group (window, "actions", G_ACTION_GROUP (win_actions));
|
||||
gtk_widget_insert_action_group (box, "actions", G_ACTION_GROUP (box_actions));
|
||||
@@ -434,7 +658,9 @@ main (int argc,
|
||||
{
|
||||
gtk_test_init (&argc, &argv);
|
||||
|
||||
g_test_add_func ("/action/inheritance", test_action);
|
||||
g_test_add_func ("/action/inheritance", test_inheritance);
|
||||
g_test_add_func ("/action/inheritance2", test_inheritance2);
|
||||
g_test_add_func ("/action/inheritance3", test_inheritance3);
|
||||
g_test_add_func ("/action/text", test_text);
|
||||
g_test_add_func ("/action/overlap", test_overlap);
|
||||
g_test_add_func ("/action/overlap2", test_overlap2);
|
||||
|
||||
@@ -114,7 +114,8 @@ test_type (gconstpointer data)
|
||||
}
|
||||
else if (g_type_is_a (type, GTK_TYPE_FILTER_LIST_MODEL) ||
|
||||
g_type_is_a (type, GTK_TYPE_NO_SELECTION) ||
|
||||
g_type_is_a (type, GTK_TYPE_SINGLE_SELECTION))
|
||||
g_type_is_a (type, GTK_TYPE_SINGLE_SELECTION) ||
|
||||
g_type_is_a (type, GTK_TYPE_MULTI_SELECTION))
|
||||
{
|
||||
GListStore *list_store = g_list_store_new (G_TYPE_OBJECT);
|
||||
instance = g_object_new (type,
|
||||
@@ -277,7 +278,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
if ((g_type_is_a (type, GTK_TYPE_FILTER_LIST_MODEL) ||
|
||||
g_type_is_a (type, GTK_TYPE_NO_SELECTION) ||
|
||||
g_type_is_a (type, GTK_TYPE_SINGLE_SELECTION)) &&
|
||||
g_type_is_a (type, GTK_TYPE_SINGLE_SELECTION) ||
|
||||
g_type_is_a (type, GTK_TYPE_MULTI_SELECTION)) &&
|
||||
strcmp (pspec->name, "model") == 0)
|
||||
continue;
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ tests = [
|
||||
['listbox'],
|
||||
['main'],
|
||||
['maplistmodel'],
|
||||
['multiselection'],
|
||||
['notify'],
|
||||
['no-gtk-init'],
|
||||
['object'],
|
||||
|
||||
@@ -0,0 +1,393 @@
|
||||
/*
|
||||
* Copyright (C) 2019, Red Hat, Inc.
|
||||
* Authors: Matthias Clasen <mclasen@redhat.com>
|
||||
*
|
||||
* 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 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/>.
|
||||
*/
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GQuark number_quark;
|
||||
static GQuark changes_quark;
|
||||
static GQuark selection_quark;
|
||||
|
||||
static guint
|
||||
get (GListModel *model,
|
||||
guint position)
|
||||
{
|
||||
GObject *object = g_list_model_get_item (model, position);
|
||||
g_assert (object != NULL);
|
||||
return GPOINTER_TO_UINT (g_object_get_qdata (object, number_quark));
|
||||
}
|
||||
|
||||
static char *
|
||||
model_to_string (GListModel *model)
|
||||
{
|
||||
GString *string = g_string_new (NULL);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < g_list_model_get_n_items (model); i++)
|
||||
{
|
||||
if (i > 0)
|
||||
g_string_append (string, " ");
|
||||
g_string_append_printf (string, "%u", get (model, i));
|
||||
}
|
||||
|
||||
return g_string_free (string, FALSE);
|
||||
}
|
||||
|
||||
static char *
|
||||
selection_to_string (GListModel *model)
|
||||
{
|
||||
GString *string = g_string_new (NULL);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < g_list_model_get_n_items (model); i++)
|
||||
{
|
||||
if (!gtk_selection_model_is_selected (GTK_SELECTION_MODEL (model), i))
|
||||
continue;
|
||||
|
||||
if (string->len > 0)
|
||||
g_string_append (string, " ");
|
||||
g_string_append_printf (string, "%u", get (model, i));
|
||||
}
|
||||
|
||||
return g_string_free (string, FALSE);
|
||||
}
|
||||
|
||||
static GListStore *
|
||||
new_store (guint start,
|
||||
guint end,
|
||||
guint step);
|
||||
|
||||
static GObject *
|
||||
make_object (guint number)
|
||||
{
|
||||
GObject *object;
|
||||
|
||||
/* 0 cannot be differentiated from NULL, so don't use it */
|
||||
g_assert (number != 0);
|
||||
|
||||
object = g_object_new (G_TYPE_OBJECT, NULL);
|
||||
g_object_set_qdata (object, number_quark, GUINT_TO_POINTER (number));
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
static void
|
||||
splice (GListStore *store,
|
||||
guint pos,
|
||||
guint removed,
|
||||
guint *numbers,
|
||||
guint added)
|
||||
{
|
||||
GObject **objects;
|
||||
guint i;
|
||||
|
||||
objects = g_new0 (GObject *, added);
|
||||
|
||||
for (i = 0; i < added; i++)
|
||||
objects[i] = make_object (numbers[i]);
|
||||
|
||||
g_list_store_splice (store, pos, removed, (gpointer *) objects, added);
|
||||
|
||||
for (i = 0; i < added; i++)
|
||||
g_object_unref (objects[i]);
|
||||
|
||||
g_free (objects);
|
||||
}
|
||||
|
||||
static void
|
||||
add (GListStore *store,
|
||||
guint number)
|
||||
{
|
||||
GObject *object = make_object (number);
|
||||
g_list_store_append (store, object);
|
||||
g_object_unref (object);
|
||||
}
|
||||
|
||||
static void
|
||||
insert (GListStore *store,
|
||||
guint position,
|
||||
guint number)
|
||||
{
|
||||
GObject *object = make_object (number);
|
||||
g_list_store_insert (store, position, object);
|
||||
g_object_unref (object);
|
||||
}
|
||||
|
||||
#define assert_model(model, expected) G_STMT_START{ \
|
||||
char *s = model_to_string (G_LIST_MODEL (model)); \
|
||||
if (!g_str_equal (s, expected)) \
|
||||
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
|
||||
#model " == " #expected, s, "==", expected); \
|
||||
g_free (s); \
|
||||
}G_STMT_END
|
||||
|
||||
#define ignore_changes(model) G_STMT_START{ \
|
||||
GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
|
||||
g_string_set_size (changes, 0); \
|
||||
}G_STMT_END
|
||||
|
||||
#define assert_changes(model, expected) G_STMT_START{ \
|
||||
GString *changes = g_object_get_qdata (G_OBJECT (model), changes_quark); \
|
||||
if (!g_str_equal (changes->str, expected)) \
|
||||
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
|
||||
#model " == " #expected, changes->str, "==", expected); \
|
||||
g_string_set_size (changes, 0); \
|
||||
}G_STMT_END
|
||||
|
||||
#define assert_selection(model, expected) G_STMT_START{ \
|
||||
char *s = selection_to_string (G_LIST_MODEL (model)); \
|
||||
if (!g_str_equal (s, expected)) \
|
||||
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
|
||||
#model " == " #expected, s, "==", expected); \
|
||||
g_free (s); \
|
||||
}G_STMT_END
|
||||
|
||||
#define ignore_selection_changes(model) G_STMT_START{ \
|
||||
GString *changes = g_object_get_qdata (G_OBJECT (model), selection_quark); \
|
||||
g_string_set_size (changes, 0); \
|
||||
}G_STMT_END
|
||||
|
||||
#define assert_selection_changes(model, expected) G_STMT_START{ \
|
||||
GString *changes = g_object_get_qdata (G_OBJECT (model), selection_quark); \
|
||||
if (!g_str_equal (changes->str, expected)) \
|
||||
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
|
||||
#model " == " #expected, changes->str, "==", expected); \
|
||||
g_string_set_size (changes, 0); \
|
||||
}G_STMT_END
|
||||
|
||||
static GListStore *
|
||||
new_empty_store (void)
|
||||
{
|
||||
return g_list_store_new (G_TYPE_OBJECT);
|
||||
}
|
||||
|
||||
static GListStore *
|
||||
new_store (guint start,
|
||||
guint end,
|
||||
guint step)
|
||||
{
|
||||
GListStore *store = new_empty_store ();
|
||||
guint i;
|
||||
|
||||
for (i = start; i <= end; i += step)
|
||||
add (store, i);
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
static void
|
||||
items_changed (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GString *changes)
|
||||
{
|
||||
g_assert (removed != 0 || added != 0);
|
||||
|
||||
if (changes->len)
|
||||
g_string_append (changes, ", ");
|
||||
|
||||
if (removed == 1 && added == 0)
|
||||
{
|
||||
g_string_append_printf (changes, "-%u", position);
|
||||
}
|
||||
else if (removed == 0 && added == 1)
|
||||
{
|
||||
g_string_append_printf (changes, "+%u", position);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_string_append_printf (changes, "%u", position);
|
||||
if (removed > 0)
|
||||
g_string_append_printf (changes, "-%u", removed);
|
||||
if (added > 0)
|
||||
g_string_append_printf (changes, "+%u", added);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
selection_changed (GListModel *model,
|
||||
guint position,
|
||||
guint n_items,
|
||||
GString *changes)
|
||||
{
|
||||
if (changes->len)
|
||||
g_string_append (changes, ", ");
|
||||
|
||||
g_string_append_printf (changes, "%u:%u", position, n_items);
|
||||
}
|
||||
|
||||
static void
|
||||
free_changes (gpointer data)
|
||||
{
|
||||
GString *changes = data;
|
||||
|
||||
/* all changes must have been checked via assert_changes() before */
|
||||
g_assert_cmpstr (changes->str, ==, "");
|
||||
|
||||
g_string_free (changes, TRUE);
|
||||
}
|
||||
|
||||
static GtkSelectionModel *
|
||||
new_model (GListStore *store)
|
||||
{
|
||||
GtkSelectionModel *result;
|
||||
GString *changes;
|
||||
|
||||
result = GTK_SELECTION_MODEL (gtk_multi_selection_new (G_LIST_MODEL (store)));
|
||||
|
||||
changes = g_string_new ("");
|
||||
g_object_set_qdata_full (G_OBJECT(result), changes_quark, changes, free_changes);
|
||||
g_signal_connect (result, "items-changed", G_CALLBACK (items_changed), changes);
|
||||
|
||||
changes = g_string_new ("");
|
||||
g_object_set_qdata_full (G_OBJECT(result), selection_quark, changes, free_changes);
|
||||
g_signal_connect (result, "selection-changed", G_CALLBACK (selection_changed), changes);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
test_create (void)
|
||||
{
|
||||
GtkSelectionModel *selection;
|
||||
GListStore *store;
|
||||
|
||||
store = new_store (1, 5, 2);
|
||||
selection = new_model (store);
|
||||
|
||||
assert_model (selection, "1 3 5");
|
||||
assert_changes (selection, "");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
g_object_unref (store);
|
||||
assert_model (selection, "1 3 5");
|
||||
assert_changes (selection, "");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
g_object_unref (selection);
|
||||
}
|
||||
|
||||
static void
|
||||
test_changes (void)
|
||||
{
|
||||
GtkSelectionModel *selection;
|
||||
GListStore *store;
|
||||
|
||||
store = new_store (1, 5, 1);
|
||||
selection = new_model (store);
|
||||
assert_model (selection, "1 2 3 4 5");
|
||||
assert_changes (selection, "");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
g_list_store_remove (store, 3);
|
||||
assert_model (selection, "1 2 3 5");
|
||||
assert_changes (selection, "-3");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
insert (store, 3, 99);
|
||||
assert_model (selection, "1 2 3 99 5");
|
||||
assert_changes (selection, "+3");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
splice (store, 3, 2, (guint[]) { 97 }, 1);
|
||||
assert_model (selection, "1 2 3 97");
|
||||
assert_changes (selection, "3-2+1");
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
g_object_unref (store);
|
||||
g_object_unref (selection);
|
||||
}
|
||||
|
||||
static void
|
||||
test_selection (void)
|
||||
{
|
||||
GtkSelectionModel *selection;
|
||||
GListStore *store;
|
||||
gboolean ret;
|
||||
|
||||
store = new_store (1, 5, 1);
|
||||
selection = new_model (store);
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
ret = gtk_selection_model_select_item (selection, 3, FALSE);
|
||||
g_assert_true (ret);
|
||||
assert_selection (selection, "4");
|
||||
assert_selection_changes (selection, "3:1");
|
||||
|
||||
ret = gtk_selection_model_unselect_item (selection, 3);
|
||||
g_assert_true (ret);
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "3:1");
|
||||
|
||||
ret = gtk_selection_model_select_item (selection, 1, FALSE);
|
||||
g_assert_true (ret);
|
||||
assert_selection (selection, "2");
|
||||
assert_selection_changes (selection, "1:1");
|
||||
|
||||
ret = gtk_selection_model_select_range (selection, 3, 2, FALSE);
|
||||
g_assert_true (ret);
|
||||
assert_selection (selection, "2 4 5");
|
||||
assert_selection_changes (selection, "3:2");
|
||||
|
||||
ret = gtk_selection_model_unselect_range (selection, 3, 2);
|
||||
g_assert_true (ret);
|
||||
assert_selection (selection, "2");
|
||||
assert_selection_changes (selection, "3:2");
|
||||
|
||||
ret = gtk_selection_model_select_all (selection);
|
||||
g_assert_true (ret);
|
||||
assert_selection (selection, "1 2 3 4 5");
|
||||
assert_selection_changes (selection, "0:5");
|
||||
|
||||
ret = gtk_selection_model_unselect_all (selection);
|
||||
g_assert_true (ret);
|
||||
assert_selection (selection, "");
|
||||
assert_selection_changes (selection, "0:5");
|
||||
|
||||
g_object_unref (store);
|
||||
g_object_unref (selection);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
setlocale (LC_ALL, "C");
|
||||
g_test_bug_base ("http://bugzilla.gnome.org/show_bug.cgi?id=%s");
|
||||
|
||||
number_quark = g_quark_from_static_string ("Hell and fire was spawned to be released.");
|
||||
changes_quark = g_quark_from_static_string ("What did I see? Can I believe what I saw?");
|
||||
selection_quark = g_quark_from_static_string ("Mana mana, badibidibi");
|
||||
|
||||
g_test_add_func ("/multiselection/create", test_create);
|
||||
#if GLIB_CHECK_VERSION (2, 58, 0) /* g_list_store_splice() is broken before 2.58 */
|
||||
g_test_add_func ("/multiselection/changes", test_changes);
|
||||
#endif
|
||||
g_test_add_func ("/multiselection/selection", test_selection);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
@@ -457,7 +457,8 @@ test_type (gconstpointer data)
|
||||
}
|
||||
else if (g_type_is_a (type, GTK_TYPE_FILTER_LIST_MODEL) ||
|
||||
g_type_is_a (type, GTK_TYPE_NO_SELECTION) ||
|
||||
g_type_is_a (type, GTK_TYPE_SINGLE_SELECTION))
|
||||
g_type_is_a (type, GTK_TYPE_SINGLE_SELECTION) ||
|
||||
g_type_is_a (type, GTK_TYPE_MULTI_SELECTION))
|
||||
{
|
||||
GListStore *list_store = g_list_store_new (G_TYPE_OBJECT);
|
||||
instance = g_object_new (type,
|
||||
|
||||
@@ -71,7 +71,8 @@ test_finalize_object (gconstpointer data)
|
||||
}
|
||||
else if (g_type_is_a (test_type, GTK_TYPE_FILTER_LIST_MODEL) ||
|
||||
g_type_is_a (test_type, GTK_TYPE_NO_SELECTION) ||
|
||||
g_type_is_a (test_type, GTK_TYPE_SINGLE_SELECTION))
|
||||
g_type_is_a (test_type, GTK_TYPE_SINGLE_SELECTION) ||
|
||||
g_type_is_a (test_type, GTK_TYPE_MULTI_SELECTION))
|
||||
{
|
||||
GListStore *list_store = g_list_store_new (G_TYPE_OBJECT);
|
||||
object = g_object_new (test_type,
|
||||
|
||||
Reference in New Issue
Block a user