Compare commits
42 Commits
selection-
...
columnview
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d17f224e71 | ||
|
|
b73be6e344 | ||
|
|
4a80f23213 | ||
|
|
3b8888acda | ||
|
|
786c95e503 | ||
|
|
7007c72fc5 | ||
|
|
9eaeb81433 | ||
|
|
3bddbcdd52 | ||
|
|
13d5d60db0 | ||
|
|
1b24528b9c | ||
|
|
6e7ebc49eb | ||
|
|
bdc6770bd9 | ||
|
|
8d2fef1e23 | ||
|
|
90668f7e01 | ||
|
|
74f72a146c | ||
|
|
5553bf1c39 | ||
|
|
77a3f81971 | ||
|
|
b3e0353e6b | ||
|
|
780915e318 | ||
|
|
7242b801ff | ||
|
|
88669080c4 | ||
|
|
51e8dc924b | ||
|
|
29b5d3ab38 | ||
|
|
bb06fffab1 | ||
|
|
94c5b00231 | ||
|
|
59e49dafd7 | ||
|
|
d5ce5b53d6 | ||
|
|
915bdf24a7 | ||
|
|
114054266b | ||
|
|
dcea6d6cda | ||
|
|
a118267ab7 | ||
|
|
cc63c581c3 | ||
|
|
dbc1a8ba11 | ||
|
|
515a86645a | ||
|
|
cbabb85e6d | ||
|
|
1031625bd4 | ||
|
|
65ed3aa1d9 | ||
|
|
ed04c46078 | ||
|
|
1b2df91e6d | ||
|
|
f745c0c2aa | ||
|
|
2ed46450ea | ||
|
|
6d168079d4 |
@@ -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 ();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -479,6 +479,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 +501,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 +512,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 +541,10 @@ 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_fixed_width
|
||||
gtk_column_view_column_get_fixed_width
|
||||
<SUBSECTION Standard>
|
||||
GTK_COLUMN_VIEW_COLUMN
|
||||
GTK_COLUMN_VIEW_COLUMN_CLASS
|
||||
@@ -554,6 +569,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
|
||||
|
||||
@@ -175,6 +175,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>
|
||||
|
||||
@@ -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 (
|
||||
@@ -691,6 +1190,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 +1198,45 @@ gtk_column_view_remove_column (GtkColumnView *self,
|
||||
g_list_store_remove (self->columns, i);
|
||||
}
|
||||
|
||||
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 +1271,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 +1374,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);
|
||||
@@ -87,6 +92,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);
|
||||
|
||||
@@ -60,6 +60,16 @@ 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;
|
||||
|
||||
GMenuModel *menu;
|
||||
|
||||
/* This list isn't sorted - this is just caching for performance */
|
||||
GtkColumnViewCell *first_cell; /* no reference, just caching */
|
||||
@@ -77,6 +87,12 @@ enum
|
||||
PROP_FACTORY,
|
||||
PROP_TITLE,
|
||||
PROP_SORTER,
|
||||
PROP_VISIBLE,
|
||||
PROP_RESIZABLE,
|
||||
PROP_EXPAND,
|
||||
PROP_REORDERABLE,
|
||||
PROP_FIXED_WIDTH,
|
||||
PROP_HEADER_MENU,
|
||||
|
||||
N_PROPS
|
||||
};
|
||||
@@ -96,6 +112,7 @@ gtk_column_view_column_dispose (GObject *object)
|
||||
g_clear_object (&self->factory);
|
||||
g_clear_object (&self->sorter);
|
||||
g_clear_pointer (&self->title, g_free);
|
||||
g_clear_object (&self->menu);
|
||||
|
||||
G_OBJECT_CLASS (gtk_column_view_column_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -126,6 +143,30 @@ 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;
|
||||
|
||||
case PROP_HEADER_MENU:
|
||||
g_value_set_object (value, self->menu);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -154,6 +195,30 @@ 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;
|
||||
|
||||
case PROP_HEADER_MENU:
|
||||
gtk_column_view_column_set_header_menu (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
@@ -217,6 +282,79 @@ 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);
|
||||
|
||||
/**
|
||||
* GtkColumnViewColumn:header-menu:
|
||||
*
|
||||
* Menu model used to create the context menu for the column header.
|
||||
*/
|
||||
properties[PROP_HEADER_MENU] =
|
||||
g_param_spec_object ("header-menu",
|
||||
P_("Header menu"),
|
||||
P_("Menu to use on the title of this column"),
|
||||
G_TYPE_MENU_MODEL,
|
||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (gobject_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
@@ -225,6 +363,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 +476,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 +524,7 @@ gtk_column_view_column_allocate (GtkColumnViewColumn *self,
|
||||
{
|
||||
self->allocation_offset = offset;
|
||||
self->allocation_size = size;
|
||||
self->header_position = offset;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -647,3 +797,298 @@ 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 (overflow != gtk_widget_get_overflow (GTK_WIDGET (self->header)))
|
||||
{
|
||||
GtkColumnViewCell *cell;
|
||||
|
||||
if (self->header)
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_column_set_header_menu:
|
||||
* @self: a #GtkColumnViewColumn
|
||||
* @menu: (allow-none): a #GMenuModel, or %NULL
|
||||
*
|
||||
* Sets the menu model that is used to create the context menu
|
||||
* for the column header.
|
||||
*/
|
||||
void
|
||||
gtk_column_view_column_set_header_menu (GtkColumnViewColumn *self,
|
||||
GMenuModel *menu)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self));
|
||||
g_return_if_fail (menu == NULL || G_IS_MENU_MODEL (menu));
|
||||
|
||||
if (!g_set_object (&self->menu, menu))
|
||||
return;
|
||||
|
||||
if (self->header)
|
||||
gtk_column_view_title_update (GTK_COLUMN_VIEW_TITLE (self->header));
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEADER_MENU]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_column_view_column_get_header_menu:
|
||||
* @self: a #GtkColumnViewColumn
|
||||
*
|
||||
* Gets the menu model that is used to create the context menu
|
||||
* for the column header.
|
||||
*
|
||||
* Returns: the #GMenuModel, or %NULL
|
||||
*/
|
||||
GMenuModel *
|
||||
gtk_column_view_column_get_header_menu (GtkColumnViewColumn *self)
|
||||
{
|
||||
g_return_val_if_fail (GTK_IS_COLUMN_VIEW_COLUMN (self), NULL);
|
||||
|
||||
return self->menu;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,41 @@ 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);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_column_view_column_set_header_menu (GtkColumnViewColumn *self,
|
||||
GMenuModel *menu);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GMenuModel * gtk_column_view_column_get_header_menu (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,
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
#include "gtkbox.h"
|
||||
#include "gtkimage.h"
|
||||
#include "gtkgestureclick.h"
|
||||
#include "gtkpopovermenu.h"
|
||||
#include "gtknative.h"
|
||||
|
||||
struct _GtkColumnViewTitle
|
||||
{
|
||||
@@ -40,6 +42,7 @@ struct _GtkColumnViewTitle
|
||||
GtkWidget *box;
|
||||
GtkWidget *title;
|
||||
GtkWidget *sort;
|
||||
GtkWidget *popup_menu;
|
||||
};
|
||||
|
||||
struct _GtkColumnViewTitleClass
|
||||
@@ -58,10 +61,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
|
||||
@@ -70,10 +81,14 @@ gtk_column_view_title_size_allocate (GtkWidget *widget,
|
||||
int height,
|
||||
int baseline)
|
||||
{
|
||||
GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (widget);
|
||||
GtkWidget *child = gtk_widget_get_first_child (widget);
|
||||
|
||||
if (child)
|
||||
gtk_widget_allocate (child, width, height, baseline, NULL);
|
||||
|
||||
if (self->popup_menu)
|
||||
gtk_native_check_resize (GTK_NATIVE (self->popup_menu));
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -82,6 +97,7 @@ gtk_column_view_title_dispose (GObject *object)
|
||||
GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (object);
|
||||
|
||||
g_clear_pointer (&self->box, gtk_widget_unparent);
|
||||
g_clear_pointer (&self->popup_menu, gtk_widget_unparent);
|
||||
|
||||
g_clear_object (&self->column);
|
||||
|
||||
@@ -112,13 +128,8 @@ gtk_column_view_title_resize_func (GtkWidget *widget)
|
||||
}
|
||||
|
||||
static void
|
||||
click_pressed_cb (GtkGestureClick *gesture,
|
||||
guint n_press,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
GtkWidget *widget)
|
||||
activate_sort (GtkColumnViewTitle *self)
|
||||
{
|
||||
GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (widget);
|
||||
GtkSorter *sorter;
|
||||
GtkColumnView *view;
|
||||
GtkColumnViewSorter *view_sorter;
|
||||
@@ -132,6 +143,56 @@ click_pressed_cb (GtkGestureClick *gesture,
|
||||
gtk_column_view_sorter_add_column (view_sorter, self->column);
|
||||
}
|
||||
|
||||
static void
|
||||
show_menu (GtkColumnViewTitle *self,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
if (!self->popup_menu)
|
||||
{
|
||||
GMenuModel *model;
|
||||
|
||||
model = gtk_column_view_column_get_header_menu (self->column);
|
||||
if (!model)
|
||||
return;
|
||||
|
||||
self->popup_menu = gtk_popover_menu_new_from_model (model);
|
||||
gtk_widget_set_parent (self->popup_menu, GTK_WIDGET (self));
|
||||
gtk_popover_set_position (GTK_POPOVER (self->popup_menu), GTK_POS_BOTTOM);
|
||||
|
||||
gtk_popover_set_has_arrow (GTK_POPOVER (self->popup_menu), FALSE);
|
||||
gtk_widget_set_halign (self->popup_menu, GTK_ALIGN_START);
|
||||
}
|
||||
|
||||
if (x != -1 && y != -1)
|
||||
{
|
||||
GdkRectangle rect = { x, y, 1, 1 };
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (self->popup_menu), &rect);
|
||||
}
|
||||
else
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (self->popup_menu), NULL);
|
||||
|
||||
gtk_popover_popup (GTK_POPOVER (self->popup_menu));
|
||||
}
|
||||
|
||||
static void
|
||||
click_released_cb (GtkGestureClick *gesture,
|
||||
guint n_press,
|
||||
double x,
|
||||
double y,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkColumnViewTitle *self = GTK_COLUMN_VIEW_TITLE (widget);
|
||||
guint button;
|
||||
|
||||
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
|
||||
|
||||
if (button == GDK_BUTTON_PRIMARY)
|
||||
activate_sort (self);
|
||||
else if (button == GDK_BUTTON_SECONDARY)
|
||||
show_menu (self, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_column_view_title_init (GtkColumnViewTitle *self)
|
||||
{
|
||||
@@ -150,7 +211,8 @@ 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);
|
||||
gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 0);
|
||||
g_signal_connect (gesture, "released", G_CALLBACK (click_released_cb), self);
|
||||
gtk_widget_add_controller (GTK_WIDGET (self), GTK_EVENT_CONTROLLER (gesture));
|
||||
}
|
||||
|
||||
@@ -199,6 +261,8 @@ gtk_column_view_title_update (GtkColumnViewTitle *self)
|
||||
}
|
||||
else
|
||||
gtk_widget_hide (self->sort);
|
||||
|
||||
g_clear_pointer (&self->popup_menu, gtk_widget_unparent);
|
||||
}
|
||||
|
||||
GtkColumnViewColumn *
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -2238,7 +2238,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 _ */
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
371
gtk/gtkmultiselection.c
Normal file
371
gtk/gtkmultiselection.c
Normal file
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
41
gtk/gtkmultiselection.h
Normal file
41
gtk/gtkmultiselection.h
Normal file
@@ -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 *model);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_MULTI_SELECTION_H__ */
|
||||
@@ -41,7 +41,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;
|
||||
@@ -331,9 +331,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,11 +348,7 @@ 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_clear_object (&priv->printers);
|
||||
|
||||
backend_parent_class->dispose (object);
|
||||
}
|
||||
@@ -411,58 +405,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 +449,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 +728,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 +736,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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -35,7 +35,6 @@
|
||||
|
||||
#include "gtkspinbutton.h"
|
||||
#include "gtkimage.h"
|
||||
#include "gtktreeselection.h"
|
||||
#include "gtknotebook.h"
|
||||
#include "gtkscrolledwindow.h"
|
||||
#include "gtkcombobox.h"
|
||||
@@ -136,14 +135,12 @@ static void gtk_print_unix_dialog_get_property (GObject *object,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void unschedule_idle_mark_conflicts (GtkPrintUnixDialog *dialog);
|
||||
static void selected_printer_changed (GtkTreeSelection *selection,
|
||||
GtkPrintUnixDialog *dialog);
|
||||
static void selected_printer_changed (GtkPrintUnixDialog *dialog);
|
||||
static void clear_per_printer_ui (GtkPrintUnixDialog *dialog);
|
||||
static void printer_added_cb (GtkPrintBackend *backend,
|
||||
GtkPrinter *printer,
|
||||
GtkPrintUnixDialog *dialog);
|
||||
static void printer_removed_cb (GtkPrintBackend *backend,
|
||||
GtkPrinter *printer,
|
||||
static void printer_added_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GtkPrintUnixDialog *dialog);
|
||||
static void printer_status_cb (GtkPrintBackend *backend,
|
||||
GtkPrinter *printer,
|
||||
@@ -171,12 +168,10 @@ static void draw_collate (GtkDrawingArea *da,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data);
|
||||
static gboolean is_printer_active (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkPrintUnixDialog *dialog);
|
||||
static gint default_printer_list_sort_func (GtkTreeModel *model,
|
||||
GtkTreeIter *a,
|
||||
GtkTreeIter *b,
|
||||
static gboolean is_printer_active (gpointer item,
|
||||
gpointer data);
|
||||
static int default_printer_list_sort_func (gconstpointer a,
|
||||
gconstpointer b,
|
||||
gpointer user_data);
|
||||
static gboolean paper_size_row_is_separator (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
@@ -198,20 +193,10 @@ static gboolean dialog_get_collate (GtkPrintUnixDialog *dialog);
|
||||
static gboolean dialog_get_reverse (GtkPrintUnixDialog *dialog);
|
||||
static gint dialog_get_n_copies (GtkPrintUnixDialog *dialog);
|
||||
|
||||
static void set_cell_sensitivity_func (GtkTreeViewColumn *tree_column,
|
||||
GtkCellRenderer *cell,
|
||||
GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
gpointer data);
|
||||
static gboolean set_active_printer (GtkPrintUnixDialog *dialog,
|
||||
const gchar *printer_name);
|
||||
static void redraw_page_layout_preview (GtkPrintUnixDialog *dialog);
|
||||
static void load_print_backends (GtkPrintUnixDialog *dialog);
|
||||
static gboolean printer_compare (GtkTreeModel *model,
|
||||
gint column,
|
||||
const gchar *key,
|
||||
GtkTreeIter *iter,
|
||||
gpointer search_data);
|
||||
static GListModel *load_print_backends (GtkPrintUnixDialog *dialog);
|
||||
|
||||
/* GtkBuildable */
|
||||
static void gtk_print_unix_dialog_buildable_init (GtkBuildableIface *iface);
|
||||
@@ -272,22 +257,11 @@ struct _GtkPrintUnixDialog
|
||||
|
||||
GtkWidget *notebook;
|
||||
|
||||
GtkWidget *printer_treeview;
|
||||
GtkTreeViewColumn *printer_icon_column;
|
||||
GtkTreeViewColumn *printer_name_column;
|
||||
GtkTreeViewColumn *printer_location_column;
|
||||
GtkTreeViewColumn *printer_status_column;
|
||||
GtkCellRenderer *printer_icon_renderer;
|
||||
GtkCellRenderer *printer_name_renderer;
|
||||
GtkCellRenderer *printer_location_renderer;
|
||||
GtkCellRenderer *printer_status_renderer;
|
||||
GtkWidget *printer_list;
|
||||
|
||||
GtkPrintCapabilities manual_capabilities;
|
||||
GtkPrintCapabilities printer_capabilities;
|
||||
|
||||
GtkTreeModel *printer_list;
|
||||
GtkTreeModelFilter *printer_list_filter;
|
||||
|
||||
GtkPageSetup *page_setup;
|
||||
gboolean page_setup_set;
|
||||
gboolean embed_page_setup;
|
||||
@@ -491,19 +465,9 @@ gtk_print_unix_dialog_class_init (GtkPrintUnixDialogClass *class)
|
||||
"/org/gtk/libgtk/ui/gtkprintunixdialog.ui");
|
||||
|
||||
/* GtkTreeView / GtkTreeModel */
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_treeview);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_list);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_list_filter);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, page_setup_list);
|
||||
gtk_widget_class_bind_template_child(widget_class, GtkPrintUnixDialog, page_setup_list);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, custom_paper_list);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_icon_column);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_name_column);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_location_column);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_status_column);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_icon_renderer);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_name_renderer);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_location_renderer);
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, printer_status_renderer);
|
||||
|
||||
/* General Widgetry */
|
||||
gtk_widget_class_bind_template_child (widget_class, GtkPrintUnixDialog, notebook);
|
||||
@@ -558,7 +522,6 @@ gtk_print_unix_dialog_class_init (GtkPrintUnixDialogClass *class)
|
||||
gtk_widget_class_bind_template_callback (widget_class, redraw_page_layout_preview);
|
||||
gtk_widget_class_bind_template_callback (widget_class, error_dialogs);
|
||||
gtk_widget_class_bind_template_callback (widget_class, emit_ok_response);
|
||||
gtk_widget_class_bind_template_callback (widget_class, selected_printer_changed);
|
||||
gtk_widget_class_bind_template_callback (widget_class, page_range_entry_focus_changed);
|
||||
gtk_widget_class_bind_template_callback (widget_class, update_page_range_entry_sensitivity);
|
||||
gtk_widget_class_bind_template_callback (widget_class, update_print_at_entry_sensitivity);
|
||||
@@ -729,11 +692,24 @@ error_dialogs (GtkPrintUnixDialog *dialog,
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
get_printer_key (GtkPrinter *printer)
|
||||
{
|
||||
return g_strconcat ("", gtk_printer_get_name (printer), " ", gtk_printer_get_location (printer), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
|
||||
{
|
||||
GtkTreeSortable *sort;
|
||||
GtkWidget *widget;
|
||||
GListModel *model;
|
||||
GListModel *sorted;
|
||||
GListModel *filtered;
|
||||
GListModel *selection;
|
||||
GtkSorter *sorter;
|
||||
GtkFilter *filter;
|
||||
GtkFilter *filter1;
|
||||
GtkExpression *expression;
|
||||
|
||||
dialog->print_backends = NULL;
|
||||
dialog->current_page = -1;
|
||||
@@ -767,43 +743,7 @@ gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
|
||||
gtk_widget_set_visible (dialog->selection_radio, FALSE);
|
||||
gtk_widget_set_visible (dialog->conflicts_widget, FALSE);
|
||||
|
||||
/* Treeview auxiliary functions need to be setup here */
|
||||
gtk_tree_model_filter_set_visible_func (dialog->printer_list_filter,
|
||||
(GtkTreeModelFilterVisibleFunc) is_printer_active,
|
||||
dialog,
|
||||
NULL);
|
||||
|
||||
sort = GTK_TREE_SORTABLE (dialog->printer_list);
|
||||
gtk_tree_sortable_set_default_sort_func (sort,
|
||||
default_printer_list_sort_func,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
gtk_tree_sortable_set_sort_column_id (sort,
|
||||
GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
|
||||
GTK_SORT_ASCENDING);
|
||||
|
||||
gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (dialog->printer_treeview),
|
||||
printer_compare, NULL, NULL);
|
||||
|
||||
gtk_tree_view_column_set_cell_data_func (dialog->printer_icon_column,
|
||||
dialog->printer_icon_renderer,
|
||||
set_cell_sensitivity_func, NULL, NULL);
|
||||
|
||||
gtk_tree_view_column_set_cell_data_func (dialog->printer_name_column,
|
||||
dialog->printer_name_renderer,
|
||||
set_cell_sensitivity_func, NULL, NULL);
|
||||
|
||||
gtk_tree_view_column_set_cell_data_func (dialog->printer_location_column,
|
||||
dialog->printer_location_renderer,
|
||||
set_cell_sensitivity_func, NULL, NULL);
|
||||
|
||||
gtk_tree_view_column_set_cell_data_func (dialog->printer_status_column,
|
||||
dialog->printer_status_renderer,
|
||||
set_cell_sensitivity_func, NULL, NULL);
|
||||
|
||||
|
||||
/* Paper size combo auxiliary funcs */
|
||||
/* Paper size combo auxilary funcs */
|
||||
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (dialog->paper_size_combo),
|
||||
paper_size_row_is_separator, NULL, NULL);
|
||||
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (dialog->paper_size_combo),
|
||||
@@ -811,7 +751,39 @@ gtk_print_unix_dialog_init (GtkPrintUnixDialog *dialog)
|
||||
page_name_func, NULL, NULL);
|
||||
|
||||
/* Load backends */
|
||||
load_print_backends (dialog);
|
||||
model = load_print_backends (dialog);
|
||||
sorter = gtk_custom_sorter_new (default_printer_list_sort_func, NULL, NULL);
|
||||
sorted = G_LIST_MODEL (gtk_sort_list_model_new (model, sorter));
|
||||
g_object_unref (sorter);
|
||||
|
||||
filter = gtk_every_filter_new ();
|
||||
|
||||
filter1 = gtk_string_filter_new ();
|
||||
gtk_string_filter_set_match_mode (GTK_STRING_FILTER (filter1), GTK_STRING_FILTER_MATCH_MODE_SUBSTRING);
|
||||
gtk_string_filter_set_ignore_case (GTK_STRING_FILTER (filter1), TRUE);
|
||||
expression = gtk_cclosure_expression_new (G_TYPE_STRING,
|
||||
NULL, 0, NULL,
|
||||
G_CALLBACK (get_printer_key),
|
||||
NULL, NULL);
|
||||
gtk_string_filter_set_expression (GTK_STRING_FILTER (filter1), expression);
|
||||
gtk_expression_unref (expression);
|
||||
gtk_multi_filter_append (GTK_MULTI_FILTER (filter), filter1);
|
||||
|
||||
filter1 = gtk_custom_filter_new (is_printer_active, dialog, NULL);
|
||||
gtk_multi_filter_append (GTK_MULTI_FILTER (filter), filter1);
|
||||
|
||||
filtered = G_LIST_MODEL (gtk_filter_list_model_new (sorted, filter));
|
||||
g_object_unref (filter);
|
||||
|
||||
selection = G_LIST_MODEL (gtk_single_selection_new (filtered));
|
||||
gtk_single_selection_set_autoselect (GTK_SINGLE_SELECTION (selection), FALSE);
|
||||
gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (selection), GTK_INVALID_LIST_POSITION);
|
||||
gtk_column_view_set_model (GTK_COLUMN_VIEW (dialog->printer_list), selection);
|
||||
g_signal_connect (selection, "items-changed", G_CALLBACK (printer_added_cb), dialog);
|
||||
g_signal_connect_swapped (selection, "notify::selected", G_CALLBACK (selected_printer_changed), dialog);
|
||||
g_object_unref (selection);
|
||||
g_object_unref (filtered);
|
||||
g_object_unref (model);
|
||||
|
||||
/* Load custom papers */
|
||||
_gtk_print_load_custom_papers (dialog->custom_paper_list);
|
||||
@@ -884,21 +856,8 @@ disconnect_printer_details_request (GtkPrintUnixDialog *dialog,
|
||||
dialog->request_details_tag = 0;
|
||||
set_busy_cursor (dialog, FALSE);
|
||||
if (details_failed)
|
||||
gtk_list_store_set (GTK_LIST_STORE (dialog->printer_list),
|
||||
g_object_get_data (G_OBJECT (dialog->request_details_printer),
|
||||
"gtk-print-tree-iter"),
|
||||
PRINTER_LIST_COL_STATE,
|
||||
_("Getting printer information failed"),
|
||||
-1);
|
||||
else
|
||||
gtk_list_store_set (GTK_LIST_STORE (dialog->printer_list),
|
||||
g_object_get_data (G_OBJECT (dialog->request_details_printer),
|
||||
"gtk-print-tree-iter"),
|
||||
PRINTER_LIST_COL_STATE,
|
||||
gtk_printer_get_state_message (dialog->request_details_printer),
|
||||
-1);
|
||||
g_object_unref (dialog->request_details_printer);
|
||||
dialog->request_details_printer = NULL;
|
||||
gtk_printer_set_state_message (dialog->request_details_printer, _("Getting printer information failed"));
|
||||
g_clear_object (&dialog->request_details_printer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -906,8 +865,6 @@ static void
|
||||
gtk_print_unix_dialog_finalize (GObject *object)
|
||||
{
|
||||
GtkPrintUnixDialog *dialog = GTK_PRINT_UNIX_DIALOG (object);
|
||||
GtkPrintBackend *backend;
|
||||
GList *node;
|
||||
|
||||
unschedule_idle_mark_conflicts (dialog);
|
||||
disconnect_printer_details_request (dialog, FALSE);
|
||||
@@ -933,18 +890,6 @@ gtk_print_unix_dialog_finalize (GObject *object)
|
||||
g_clear_pointer (&dialog->waiting_for_printer, (GDestroyNotify)g_free);
|
||||
g_clear_pointer (&dialog->format_for_printer, (GDestroyNotify)g_free);
|
||||
|
||||
for (node = dialog->print_backends; node != NULL; node = node->next)
|
||||
{
|
||||
backend = GTK_PRINT_BACKEND (node->data);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (backend, printer_added_cb, dialog);
|
||||
g_signal_handlers_disconnect_by_func (backend, printer_removed_cb, dialog);
|
||||
g_signal_handlers_disconnect_by_func (backend, printer_status_cb, dialog);
|
||||
|
||||
gtk_print_backend_destroy (backend);
|
||||
g_object_unref (backend);
|
||||
}
|
||||
|
||||
g_list_free (dialog->print_backends);
|
||||
dialog->print_backends = NULL;
|
||||
|
||||
@@ -953,17 +898,6 @@ gtk_print_unix_dialog_finalize (GObject *object)
|
||||
G_OBJECT_CLASS (gtk_print_unix_dialog_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
printer_removed_cb (GtkPrintBackend *backend,
|
||||
GtkPrinter *printer,
|
||||
GtkPrintUnixDialog *dialog)
|
||||
{
|
||||
GtkTreeIter *iter;
|
||||
|
||||
iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
|
||||
gtk_list_store_remove (GTK_LIST_STORE (dialog->printer_list), iter);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_print_unix_dialog_buildable_init (GtkBuildableIface *iface)
|
||||
{
|
||||
@@ -985,157 +919,68 @@ gtk_print_unix_dialog_buildable_get_internal_child (GtkBuildable *buildable,
|
||||
return parent_buildable_iface->get_internal_child (buildable, builder, childname);
|
||||
}
|
||||
|
||||
/* This function controls "sensitive" property of GtkCellRenderer
|
||||
* based on pause state of printers.
|
||||
*/
|
||||
void set_cell_sensitivity_func (GtkTreeViewColumn *tree_column,
|
||||
GtkCellRenderer *cell,
|
||||
GtkTreeModel *tree_model,
|
||||
GtkTreeIter *iter,
|
||||
gpointer data)
|
||||
{
|
||||
GtkPrinter *printer;
|
||||
|
||||
gtk_tree_model_get (tree_model, iter,
|
||||
PRINTER_LIST_COL_PRINTER_OBJ, &printer,
|
||||
-1);
|
||||
|
||||
if (printer != NULL && !gtk_printer_is_accepting_jobs (printer))
|
||||
g_object_set (cell, "sensitive", FALSE, NULL);
|
||||
else
|
||||
g_object_set (cell, "sensitive", TRUE, NULL);
|
||||
|
||||
g_clear_object (&printer);
|
||||
}
|
||||
|
||||
static void
|
||||
printer_status_cb (GtkPrintBackend *backend,
|
||||
GtkPrinter *printer,
|
||||
GtkPrintUnixDialog *dialog)
|
||||
{
|
||||
GtkTreeIter *iter;
|
||||
GtkTreeSelection *selection;
|
||||
GIcon *icon;
|
||||
|
||||
iter = g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter");
|
||||
|
||||
icon = g_themed_icon_new ("printer");
|
||||
g_themed_icon_prepend_name (G_THEMED_ICON (icon), gtk_printer_get_icon_name (printer));
|
||||
gtk_list_store_set (GTK_LIST_STORE (dialog->printer_list), iter,
|
||||
PRINTER_LIST_COL_ICON, icon,
|
||||
PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
|
||||
PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
|
||||
PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
|
||||
-1);
|
||||
g_object_unref (icon);
|
||||
GListModel *model;
|
||||
|
||||
/* When the pause state change then we need to update sensitive property
|
||||
* of GTK_RESPONSE_OK button inside of selected_printer_changed function.
|
||||
*/
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->printer_treeview));
|
||||
dialog->internal_printer_change = TRUE;
|
||||
selected_printer_changed (selection, dialog);
|
||||
dialog->internal_printer_change = FALSE;
|
||||
selected_printer_changed (dialog);
|
||||
|
||||
model = gtk_column_view_get_model (GTK_COLUMN_VIEW (dialog->printer_list));
|
||||
|
||||
if (gtk_print_backend_printer_list_is_done (backend) &&
|
||||
gtk_printer_is_default (printer) &&
|
||||
(gtk_tree_selection_count_selected_rows (selection) == 0))
|
||||
gtk_single_selection_get_selected (GTK_SINGLE_SELECTION (model)) == GTK_INVALID_LIST_POSITION)
|
||||
set_active_printer (dialog, gtk_printer_get_name (printer));
|
||||
}
|
||||
|
||||
static void
|
||||
printer_added_cb (GtkPrintBackend *backend,
|
||||
GtkPrinter *printer,
|
||||
printer_added_cb (GListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
GtkPrintUnixDialog *dialog)
|
||||
{
|
||||
GtkTreeIter iter, filter_iter;
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreePath *path;
|
||||
GIcon *icon;
|
||||
guint i;
|
||||
|
||||
gtk_list_store_append (GTK_LIST_STORE (dialog->printer_list), &iter);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (printer),
|
||||
"gtk-print-tree-iter",
|
||||
gtk_tree_iter_copy (&iter),
|
||||
(GDestroyNotify) gtk_tree_iter_free);
|
||||
|
||||
icon = g_themed_icon_new ("printer");
|
||||
g_themed_icon_prepend_name (G_THEMED_ICON (icon), gtk_printer_get_icon_name (printer));
|
||||
gtk_list_store_set (GTK_LIST_STORE (dialog->printer_list), &iter,
|
||||
PRINTER_LIST_COL_ICON, icon,
|
||||
PRINTER_LIST_COL_NAME, gtk_printer_get_name (printer),
|
||||
PRINTER_LIST_COL_STATE, gtk_printer_get_state_message (printer),
|
||||
PRINTER_LIST_COL_JOBS, gtk_printer_get_job_count (printer),
|
||||
PRINTER_LIST_COL_LOCATION, gtk_printer_get_location (printer),
|
||||
PRINTER_LIST_COL_PRINTER_OBJ, printer,
|
||||
-1);
|
||||
g_object_unref (icon);
|
||||
|
||||
gtk_tree_model_filter_convert_child_iter_to_iter (dialog->printer_list_filter,
|
||||
&filter_iter, &iter);
|
||||
path = gtk_tree_model_get_path (GTK_TREE_MODEL (dialog->printer_list_filter), &filter_iter);
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->printer_treeview));
|
||||
|
||||
if (dialog->waiting_for_printer != NULL &&
|
||||
strcmp (gtk_printer_get_name (printer), dialog->waiting_for_printer) == 0)
|
||||
for (i = position; i < position + added; i++)
|
||||
{
|
||||
dialog->internal_printer_change = TRUE;
|
||||
gtk_tree_selection_select_iter (selection, &filter_iter);
|
||||
gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (dialog->printer_treeview),
|
||||
path, NULL, TRUE, 0.5, 0.0);
|
||||
dialog->internal_printer_change = FALSE;
|
||||
g_free (dialog->waiting_for_printer);
|
||||
dialog->waiting_for_printer = NULL;
|
||||
}
|
||||
else if (is_default_printer (dialog, printer) &&
|
||||
gtk_tree_selection_count_selected_rows (selection) == 0)
|
||||
{
|
||||
dialog->internal_printer_change = TRUE;
|
||||
gtk_tree_selection_select_iter (selection, &filter_iter);
|
||||
gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (dialog->printer_treeview),
|
||||
path, NULL, TRUE, 0.5, 0.0);
|
||||
dialog->internal_printer_change = FALSE;
|
||||
}
|
||||
GtkPrinter *printer = g_list_model_get_item (model, i);
|
||||
|
||||
gtk_tree_path_free (path);
|
||||
if (dialog->waiting_for_printer != NULL &&
|
||||
strcmp (gtk_printer_get_name (printer), dialog->waiting_for_printer) == 0)
|
||||
{
|
||||
gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (model), i);
|
||||
g_free (dialog->waiting_for_printer);
|
||||
dialog->waiting_for_printer = NULL;
|
||||
g_object_unref (printer);
|
||||
return;
|
||||
}
|
||||
else if (is_default_printer (dialog, printer) &&
|
||||
gtk_single_selection_get_selected (GTK_SINGLE_SELECTION (model)) == GTK_INVALID_LIST_POSITION)
|
||||
{
|
||||
gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (model), i);
|
||||
g_object_unref (printer);
|
||||
return;
|
||||
}
|
||||
|
||||
g_object_unref (printer);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
printer_list_initialize (GtkPrintUnixDialog *dialog,
|
||||
GtkPrintBackend *print_backend)
|
||||
{
|
||||
GList *list;
|
||||
GList *node;
|
||||
|
||||
g_return_if_fail (print_backend != NULL);
|
||||
|
||||
g_signal_connect_object (print_backend, "printer-added",
|
||||
(GCallback) printer_added_cb, G_OBJECT (dialog), 0);
|
||||
|
||||
g_signal_connect_object (print_backend, "printer-removed",
|
||||
(GCallback) printer_removed_cb, G_OBJECT (dialog), 0);
|
||||
|
||||
g_signal_connect_object (print_backend, "printer-status-changed",
|
||||
(GCallback) printer_status_cb, G_OBJECT (dialog), 0);
|
||||
|
||||
list = gtk_print_backend_get_printer_list (print_backend);
|
||||
|
||||
node = list;
|
||||
while (node != NULL)
|
||||
{
|
||||
printer_added_cb (print_backend, node->data, dialog);
|
||||
node = node->next;
|
||||
}
|
||||
|
||||
g_list_free (list);
|
||||
}
|
||||
|
||||
static void
|
||||
static GListModel *
|
||||
load_print_backends (GtkPrintUnixDialog *dialog)
|
||||
{
|
||||
GList *node;
|
||||
GListStore *lists;
|
||||
GListModel *model;
|
||||
|
||||
lists = g_list_store_new (G_TYPE_LIST_MODEL);
|
||||
|
||||
if (g_module_supported ())
|
||||
dialog->print_backends = gtk_print_backend_load_modules ();
|
||||
@@ -1143,8 +988,17 @@ load_print_backends (GtkPrintUnixDialog *dialog)
|
||||
for (node = dialog->print_backends; node != NULL; node = node->next)
|
||||
{
|
||||
GtkPrintBackend *backend = node->data;
|
||||
printer_list_initialize (dialog, backend);
|
||||
|
||||
g_signal_connect_object (backend, "printer-status-changed",
|
||||
G_CALLBACK (printer_status_cb), G_OBJECT (dialog), 0);
|
||||
g_list_store_append (lists, gtk_print_backend_get_printers (backend));
|
||||
}
|
||||
|
||||
model = G_LIST_MODEL (gtk_flatten_list_model_new (GTK_TYPE_PRINTER, G_LIST_MODEL (lists)));
|
||||
|
||||
g_object_unref (lists);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1226,19 +1080,11 @@ gtk_print_unix_dialog_get_property (GObject *object,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_printer_active (GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
GtkPrintUnixDialog *dialog)
|
||||
is_printer_active (gpointer item, gpointer data)
|
||||
{
|
||||
GtkPrinter *printer = item;
|
||||
GtkPrintUnixDialog *dialog = data;
|
||||
gboolean result;
|
||||
GtkPrinter *printer;
|
||||
|
||||
gtk_tree_model_get (model, iter,
|
||||
PRINTER_LIST_COL_PRINTER_OBJ, &printer,
|
||||
-1);
|
||||
|
||||
if (printer == NULL)
|
||||
return FALSE;
|
||||
|
||||
result = gtk_printer_is_active (printer);
|
||||
|
||||
@@ -1255,61 +1101,44 @@ is_printer_active (GtkTreeModel *model,
|
||||
gtk_printer_accepts_ps (printer));
|
||||
}
|
||||
|
||||
g_object_unref (printer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gint
|
||||
default_printer_list_sort_func (GtkTreeModel *model,
|
||||
GtkTreeIter *a,
|
||||
GtkTreeIter *b,
|
||||
static int
|
||||
default_printer_list_sort_func (gconstpointer a,
|
||||
gconstpointer b,
|
||||
gpointer user_data)
|
||||
{
|
||||
gchar *a_name;
|
||||
gchar *b_name;
|
||||
GtkPrinter *a_printer;
|
||||
GtkPrinter *b_printer;
|
||||
gint result;
|
||||
|
||||
gtk_tree_model_get (model, a,
|
||||
PRINTER_LIST_COL_NAME, &a_name,
|
||||
PRINTER_LIST_COL_PRINTER_OBJ, &a_printer,
|
||||
-1);
|
||||
gtk_tree_model_get (model, b,
|
||||
PRINTER_LIST_COL_NAME, &b_name,
|
||||
PRINTER_LIST_COL_PRINTER_OBJ, &b_printer,
|
||||
-1);
|
||||
GtkPrinter *a_printer = (gpointer)a;
|
||||
GtkPrinter *b_printer = (gpointer)b;
|
||||
const char *a_name;
|
||||
const char *b_name;
|
||||
|
||||
if (a_printer == NULL && b_printer == NULL)
|
||||
result = 0;
|
||||
return 0;
|
||||
else if (a_printer == NULL)
|
||||
result = G_MAXINT;
|
||||
return 1;
|
||||
else if (b_printer == NULL)
|
||||
result = G_MININT;
|
||||
else if (gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
|
||||
result = 0;
|
||||
return -1;
|
||||
|
||||
if (gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
|
||||
return 0;
|
||||
else if (gtk_printer_is_virtual (a_printer) && !gtk_printer_is_virtual (b_printer))
|
||||
result = G_MININT;
|
||||
return -1;
|
||||
else if (!gtk_printer_is_virtual (a_printer) && gtk_printer_is_virtual (b_printer))
|
||||
result = G_MAXINT;
|
||||
else if (a_name == NULL && b_name == NULL)
|
||||
result = 0;
|
||||
return 1;
|
||||
|
||||
a_name = gtk_printer_get_name (a_printer);
|
||||
b_name = gtk_printer_get_name (b_printer);
|
||||
|
||||
if (a_name == NULL && b_name == NULL)
|
||||
return 0;
|
||||
else if (a_name == NULL && b_name != NULL)
|
||||
result = 1;
|
||||
return 1;
|
||||
else if (a_name != NULL && b_name == NULL)
|
||||
result = -1;
|
||||
else
|
||||
result = g_ascii_strcasecmp (a_name, b_name);
|
||||
return -1;
|
||||
|
||||
g_free (a_name);
|
||||
g_free (b_name);
|
||||
if (a_printer)
|
||||
g_object_unref (a_printer);
|
||||
if (b_printer)
|
||||
g_object_unref (b_printer);
|
||||
|
||||
return result;
|
||||
return g_ascii_strcasecmp (a_name, b_name);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
@@ -1697,8 +1526,6 @@ update_dialog_from_capabilities (GtkPrintUnixDialog *dialog)
|
||||
gtk_widget_set_visible (button, (caps & GTK_PRINT_CAPABILITY_PREVIEW) != 0);
|
||||
|
||||
update_collate_icon (NULL, dialog);
|
||||
|
||||
gtk_tree_model_filter_refilter (dialog->printer_list_filter);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -1901,17 +1728,12 @@ mark_conflicts (GtkPrintUnixDialog *dialog)
|
||||
|
||||
if (printer)
|
||||
{
|
||||
|
||||
g_signal_handler_block (dialog->options,
|
||||
dialog->options_changed_handler);
|
||||
g_signal_handler_block (dialog->options, dialog->options_changed_handler);
|
||||
|
||||
gtk_printer_option_set_clear_conflicts (dialog->options);
|
||||
have_conflict = _gtk_printer_mark_conflicts (printer, dialog->options);
|
||||
|
||||
have_conflict = _gtk_printer_mark_conflicts (printer,
|
||||
dialog->options);
|
||||
|
||||
g_signal_handler_unblock (dialog->options,
|
||||
dialog->options_changed_handler);
|
||||
g_signal_handler_unblock (dialog->options, dialog->options_changed_handler);
|
||||
}
|
||||
|
||||
if (have_conflict)
|
||||
@@ -1989,20 +1811,14 @@ printer_details_acquired (GtkPrinter *printer,
|
||||
disconnect_printer_details_request (dialog, !success);
|
||||
|
||||
if (success)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->printer_treeview));
|
||||
|
||||
selected_printer_changed (selection, dialog);
|
||||
}
|
||||
selected_printer_changed (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
selected_printer_changed (GtkTreeSelection *selection,
|
||||
GtkPrintUnixDialog *dialog)
|
||||
selected_printer_changed (GtkPrintUnixDialog *dialog)
|
||||
{
|
||||
GListModel *model = gtk_column_view_get_model (GTK_COLUMN_VIEW (dialog->printer_list));
|
||||
GtkPrinter *printer;
|
||||
GtkTreeIter iter, filter_iter;
|
||||
|
||||
/* Whenever the user selects a printer we stop looking for
|
||||
* the printer specified in the initial settings
|
||||
@@ -2016,17 +1832,7 @@ selected_printer_changed (GtkTreeSelection *selection,
|
||||
|
||||
disconnect_printer_details_request (dialog, FALSE);
|
||||
|
||||
printer = NULL;
|
||||
if (gtk_tree_selection_get_selected (selection, NULL, &filter_iter))
|
||||
{
|
||||
gtk_tree_model_filter_convert_iter_to_child_iter (dialog->printer_list_filter,
|
||||
&iter,
|
||||
&filter_iter);
|
||||
|
||||
gtk_tree_model_get (dialog->printer_list, &iter,
|
||||
PRINTER_LIST_COL_PRINTER_OBJ, &printer,
|
||||
-1);
|
||||
}
|
||||
printer = gtk_single_selection_get_selected_item (GTK_SINGLE_SELECTION (model));
|
||||
|
||||
/* sets GTK_RESPONSE_OK button sensitivity depending on whether the printer
|
||||
* accepts/rejects jobs
|
||||
@@ -2036,33 +1842,24 @@ selected_printer_changed (GtkTreeSelection *selection,
|
||||
if (!gtk_printer_is_accepting_jobs (printer))
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
|
||||
else if (dialog->current_printer == printer && gtk_printer_has_details (printer))
|
||||
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
|
||||
}
|
||||
|
||||
if (printer != NULL && !gtk_printer_has_details (printer))
|
||||
{
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE);
|
||||
dialog->request_details_tag =
|
||||
g_signal_connect (printer, "details-acquired",
|
||||
G_CALLBACK (printer_details_acquired), dialog);
|
||||
/* take the reference */
|
||||
dialog->request_details_printer = printer;
|
||||
dialog->request_details_tag = g_signal_connect (printer, "details-acquired",
|
||||
G_CALLBACK (printer_details_acquired), dialog);
|
||||
|
||||
dialog->request_details_printer = g_object_ref (printer);
|
||||
set_busy_cursor (dialog, TRUE);
|
||||
gtk_list_store_set (GTK_LIST_STORE (dialog->printer_list),
|
||||
g_object_get_data (G_OBJECT (printer), "gtk-print-tree-iter"),
|
||||
PRINTER_LIST_COL_STATE, _("Getting printer information…"),
|
||||
-1);
|
||||
gtk_printer_set_state_message (printer, _("Getting printer information…"));
|
||||
gtk_printer_request_details (printer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (printer == dialog->current_printer)
|
||||
{
|
||||
if (printer)
|
||||
g_object_unref (printer);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
if (dialog->options)
|
||||
{
|
||||
@@ -2075,7 +1872,7 @@ selected_printer_changed (GtkTreeSelection *selection,
|
||||
|
||||
if (printer != NULL && gtk_printer_is_accepting_jobs (printer))
|
||||
gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE);
|
||||
dialog->current_printer = printer;
|
||||
dialog->current_printer = g_object_ref (printer);
|
||||
|
||||
if (printer != NULL)
|
||||
{
|
||||
@@ -2114,86 +1911,7 @@ selected_printer_changed (GtkTreeSelection *selection,
|
||||
update_paper_sizes (dialog);
|
||||
dialog->internal_page_setup_change = FALSE;
|
||||
|
||||
g_object_notify ( G_OBJECT(dialog), "selected-printer");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
printer_compare (GtkTreeModel *model,
|
||||
gint column,
|
||||
const gchar *key,
|
||||
GtkTreeIter *iter,
|
||||
gpointer search_data)
|
||||
{
|
||||
gboolean matches = FALSE;
|
||||
|
||||
if (key != NULL)
|
||||
{
|
||||
gchar *name = NULL;
|
||||
gchar *location = NULL;
|
||||
gchar *casefold_key = NULL;
|
||||
gchar *casefold_name = NULL;
|
||||
gchar *casefold_location = NULL;
|
||||
gchar **keys;
|
||||
gchar *tmp1, *tmp2;
|
||||
gint i;
|
||||
|
||||
gtk_tree_model_get (model, iter,
|
||||
PRINTER_LIST_COL_NAME, &name,
|
||||
PRINTER_LIST_COL_LOCATION, &location,
|
||||
-1);
|
||||
|
||||
casefold_key = g_utf8_casefold (key, -1);
|
||||
|
||||
if (name != NULL)
|
||||
{
|
||||
casefold_name = g_utf8_casefold (name, -1);
|
||||
g_free (name);
|
||||
}
|
||||
|
||||
if (location != NULL)
|
||||
{
|
||||
casefold_location = g_utf8_casefold (location, -1);
|
||||
g_free (location);
|
||||
}
|
||||
|
||||
if (casefold_name != NULL ||
|
||||
casefold_location != NULL)
|
||||
{
|
||||
keys = g_strsplit_set (casefold_key, " \t", 0);
|
||||
if (keys != NULL)
|
||||
{
|
||||
matches = TRUE;
|
||||
|
||||
for (i = 0; keys[i] != NULL; i++)
|
||||
{
|
||||
if (keys[i][0] != '\0')
|
||||
{
|
||||
tmp1 = tmp2 = NULL;
|
||||
|
||||
if (casefold_name != NULL)
|
||||
tmp1 = g_strstr_len (casefold_name, -1, keys[i]);
|
||||
|
||||
if (casefold_location != NULL)
|
||||
tmp2 = g_strstr_len (casefold_location, -1, keys[i]);
|
||||
|
||||
if (tmp1 == NULL && tmp2 == NULL)
|
||||
{
|
||||
matches = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_strfreev (keys);
|
||||
}
|
||||
}
|
||||
|
||||
g_free (casefold_location);
|
||||
g_free (casefold_name);
|
||||
g_free (casefold_key);
|
||||
}
|
||||
|
||||
return !matches;
|
||||
g_object_notify (G_OBJECT (dialog), "selected-printer");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -3488,42 +3206,28 @@ static gboolean
|
||||
set_active_printer (GtkPrintUnixDialog *dialog,
|
||||
const gchar *printer_name)
|
||||
{
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter, filter_iter;
|
||||
GtkTreeSelection *selection;
|
||||
GListModel *model;
|
||||
GtkPrinter *printer;
|
||||
guint i;
|
||||
|
||||
model = GTK_TREE_MODEL (dialog->printer_list);
|
||||
model = gtk_column_view_get_model (GTK_COLUMN_VIEW (dialog->printer_list));
|
||||
|
||||
if (gtk_tree_model_get_iter_first (model, &iter))
|
||||
for (i = 0; i < g_list_model_get_n_items (model); i++)
|
||||
{
|
||||
do
|
||||
printer = g_list_model_get_item (model, i);
|
||||
|
||||
if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
|
||||
{
|
||||
gtk_tree_model_get (GTK_TREE_MODEL (dialog->printer_list), &iter,
|
||||
PRINTER_LIST_COL_PRINTER_OBJ, &printer,
|
||||
-1);
|
||||
if (printer == NULL)
|
||||
continue;
|
||||
gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (model), i);
|
||||
|
||||
if (strcmp (gtk_printer_get_name (printer), printer_name) == 0)
|
||||
{
|
||||
gtk_tree_model_filter_convert_child_iter_to_iter (dialog->printer_list_filter,
|
||||
&filter_iter, &iter);
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->printer_treeview));
|
||||
dialog->internal_printer_change = TRUE;
|
||||
gtk_tree_selection_select_iter (selection, &filter_iter);
|
||||
dialog->internal_printer_change = FALSE;
|
||||
g_free (dialog->waiting_for_printer);
|
||||
dialog->waiting_for_printer = NULL;
|
||||
|
||||
g_object_unref (printer);
|
||||
return TRUE;
|
||||
}
|
||||
g_free (dialog->waiting_for_printer);
|
||||
dialog->waiting_for_printer = NULL;
|
||||
|
||||
g_object_unref (printer);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
} while (gtk_tree_model_iter_next (model, &iter));
|
||||
g_object_unref (printer);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
@@ -3697,13 +3401,8 @@ gtk_print_unix_dialog_set_manual_capabilities (GtkPrintUnixDialog *dialog,
|
||||
|
||||
if (dialog->current_printer)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (dialog->printer_treeview));
|
||||
g_clear_object (&dialog->current_printer);
|
||||
dialog->internal_printer_change = TRUE;
|
||||
selected_printer_changed (selection, dialog);
|
||||
dialog->internal_printer_change = FALSE;
|
||||
selected_printer_changed (dialog);
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (dialog), "manual-capabilities");
|
||||
|
||||
351
gtk/gtkset.c
Normal file
351
gtk/gtkset.c
Normal file
@@ -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 negatie 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
|
||||
70
gtk/gtkset.h
Normal file
70
gtk/gtkset.h
Normal file
@@ -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__ */
|
||||
@@ -192,21 +192,6 @@ G_DEFINE_TYPE_EXTENDED (GtkSingleSelection, gtk_single_selection, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_SELECTION_MODEL,
|
||||
gtk_single_selection_selection_model_init))
|
||||
|
||||
static void
|
||||
emit_selection_changed (GtkSelectionModel *self,
|
||||
int old_position,
|
||||
int position)
|
||||
{
|
||||
if (old_position == GTK_INVALID_LIST_POSITION)
|
||||
gtk_selection_model_selection_changed (self, position, 1);
|
||||
else if (position == GTK_INVALID_LIST_POSITION)
|
||||
gtk_selection_model_selection_changed (self, old_position, 1);
|
||||
else if (position < old_position)
|
||||
gtk_selection_model_selection_changed (self, position, old_position - position + 1);
|
||||
else
|
||||
gtk_selection_model_selection_changed (self, old_position, position - old_position + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_single_selection_items_changed_cb (GListModel *model,
|
||||
guint position,
|
||||
@@ -215,9 +200,6 @@ gtk_single_selection_items_changed_cb (GListModel *model,
|
||||
GtkSingleSelection *self)
|
||||
{
|
||||
g_object_freeze_notify (G_OBJECT (self));
|
||||
int selected_before;
|
||||
|
||||
selected_before = self->selected;
|
||||
|
||||
if (self->selected_item == NULL)
|
||||
{
|
||||
@@ -313,9 +295,6 @@ gtk_single_selection_items_changed_cb (GListModel *model,
|
||||
|
||||
g_list_model_items_changed (G_LIST_MODEL (self), position, removed, added);
|
||||
|
||||
if (self->selected != selected_before)
|
||||
emit_selection_changed (GTK_SELECTION_MODEL (self), selected_before, self->selected);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (self));
|
||||
}
|
||||
|
||||
@@ -584,7 +563,14 @@ gtk_single_selection_set_selected (GtkSingleSelection *self,
|
||||
g_clear_object (&self->selected_item);
|
||||
self->selected_item = new_selected;
|
||||
|
||||
emit_selection_changed (GTK_SELECTION_MODEL (self), old_position, position);
|
||||
if (old_position == GTK_INVALID_LIST_POSITION)
|
||||
gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), position, 1);
|
||||
else if (position == GTK_INVALID_LIST_POSITION)
|
||||
gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), old_position, 1);
|
||||
else if (position < old_position)
|
||||
gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), position, old_position - position + 1);
|
||||
else
|
||||
gtk_selection_model_selection_changed (GTK_SELECTION_MODEL (self), old_position, position - old_position + 1);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED]);
|
||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SELECTED_ITEM]);
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
<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"/>
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
<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"/>
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="path">
|
||||
<property name="title" translatable="yes">Path</property>
|
||||
<property name="expand">1</property>
|
||||
<property name="factory">
|
||||
<object class="GtkSignalListItemFactory">
|
||||
<signal name="setup" handler="setup_name_cb"/>
|
||||
@@ -92,6 +93,11 @@
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn" id="filler">
|
||||
<property name="expand">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
@@ -135,6 +135,7 @@ gtk_private_sources = files([
|
||||
'gtkscaler.c',
|
||||
'gtksearchengine.c',
|
||||
'gtksearchenginemodel.c',
|
||||
'gtkset.c',
|
||||
'gtksizerequestcache.c',
|
||||
'gtkstyleanimation.c',
|
||||
'gtkstylecascade.c',
|
||||
@@ -303,6 +304,7 @@ gtk_public_sources = files([
|
||||
'gtkmodules.c',
|
||||
'gtkmountoperation.c',
|
||||
'gtkmultifilter.c',
|
||||
'gtkmultiselection.c',
|
||||
'gtkmultisorter.c',
|
||||
'gtknativedialog.c',
|
||||
'gtknomediafile.c',
|
||||
@@ -577,6 +579,7 @@ gtk_public_headers = files([
|
||||
'gtkmessagedialog.h',
|
||||
'gtkmountoperation.h',
|
||||
'gtkmultifilter.h',
|
||||
'gtkmultiselection.h',
|
||||
'gtkmultisorter.h',
|
||||
'gtknative.h',
|
||||
'gtknativedialog.h',
|
||||
|
||||
@@ -17,19 +17,6 @@
|
||||
<column type="gboolean"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkListStore" id="printer_list">
|
||||
<columns>
|
||||
<column type="GIcon"/>
|
||||
<column type="gchararray"/>
|
||||
<column type="gchararray"/>
|
||||
<column type="gint"/>
|
||||
<column type="gchararray"/>
|
||||
<column type="GObject"/>
|
||||
</columns>
|
||||
</object>
|
||||
<object class="GtkTreeModelFilter" id="printer_list_filter">
|
||||
<property name="child-model">printer_list</property>
|
||||
</object>
|
||||
<object class="GtkAdjustment" id="scale_spin_adjustment">
|
||||
<property name="lower">1</property>
|
||||
<property name="upper">1000</property>
|
||||
@@ -72,58 +59,131 @@
|
||||
<property name="has-frame">1</property>
|
||||
<property name="vexpand">1</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="printer_treeview">
|
||||
<property name="model">printer_list_filter</property>
|
||||
<signal name="row-activated" handler="emit_ok_response" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection" id="treeview-selection1">
|
||||
<property name="mode">browse</property>
|
||||
<signal name="changed" handler="selected_printer_changed" swapped="no"/>
|
||||
</object>
|
||||
</child>
|
||||
<object class="GtkColumnView" id="printer_list">
|
||||
<property name="can-focus">1</property>
|
||||
<property name="halign">fill</property>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="printer_icon_column">
|
||||
<child>
|
||||
<object class="GtkCellRendererPixbuf" id="printer_icon_renderer"/>
|
||||
<attributes>
|
||||
<attribute name="gicon">0</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="printer_name_column">
|
||||
<property name="title" translatable="yes">Printer</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="printer_name_renderer"/>
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="printer_location_column">
|
||||
<property name="title" translatable="yes" comments="this is the header for the location column in the print dialog">Location</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="printer_location_renderer"/>
|
||||
<attributes>
|
||||
<attribute name="text">4</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkTreeViewColumn" id="printer_status_column">
|
||||
<property name="title" translatable="yes" comments="this is the header for the printer status column in the print dialog">Status</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" id="printer_status_renderer">
|
||||
<property name="ellipsize">end</property>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<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="GtkImage">
|
||||
<binding name="icon-name">
|
||||
<lookup name="icon-name" type="GtkPrinter">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<binding name="sensitive">
|
||||
<lookup name="accepting-jobs" type="GtkPrinter">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
<attributes>
|
||||
<attribute name="text">2</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes">Name</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="name" type="GtkPrinter">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<binding name="sensitive">
|
||||
<lookup name="accepting-jobs" type="GtkPrinter">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes" comments="this is the header for the location column in the print dialog">Location</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="location" type="GtkPrinter">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<binding name="sensitive">
|
||||
<lookup name="accepting-jobs" type="GtkPrinter">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkColumnViewColumn">
|
||||
<property name="title" translatable="yes" comments="this is the header for the printer status column in the print dialog">Status</property>
|
||||
<property name="expand">1</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>
|
||||
<property name="ellipsize">end</property>
|
||||
<binding name="label">
|
||||
<lookup name="state-message" type="GtkPrinter">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
<binding name="sensitive">
|
||||
<lookup name="accepting-jobs" type="GtkPrinter">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
</lookup>
|
||||
</binding>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
]]></property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
||||
@@ -9,8 +9,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gtk+ 2.4.0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-05-31 05:35+0000\n"
|
||||
"PO-Revision-Date: 2020-05-31 09:11+0300\n"
|
||||
"POT-Creation-Date: 2020-05-28 09:12+0000\n"
|
||||
"PO-Revision-Date: 2020-05-28 13:03+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:745 gtk/gtkmenubutton.c:422
|
||||
#: gtk/gtkframe.c:168 gtk/gtklabel.c:746 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:766 gtk/gtkmenubutton.c:429 gtk/gtkstack.c:431
|
||||
#: gtk/gtklabel.c:767 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:767 gtk/gtkmenubutton.c:430
|
||||
#: gtk/gtklabel.c:768 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:758 gtk/gtksearchbar.c:316 gtk/gtkstack.c:381
|
||||
#: gtk/gtkscrolledwindow.c:759 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:759 gtk/gtksearchbar.c:317 gtk/gtkviewport.c:391
|
||||
#: gtk/gtkscrolledwindow.c:760 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:472 gtk/gtktreeviewcolumn.c:304
|
||||
#: gtk/gtkiconview.c:473 gtk/gtktreeviewcolumn.c:304
|
||||
msgid "Spacing"
|
||||
msgstr "Інтервал"
|
||||
|
||||
@@ -840,27 +840,27 @@ msgstr "Розподілити рівномірно за простором"
|
||||
msgid "Spacing between widgets"
|
||||
msgstr "Інтервал між віджетами"
|
||||
|
||||
#: gtk/gtkbuilder.c:313
|
||||
#: gtk/gtkbuilder.c:311
|
||||
msgid "Translation Domain"
|
||||
msgstr "Домен перекладу"
|
||||
|
||||
#: gtk/gtkbuilder.c:314
|
||||
#: gtk/gtkbuilder.c:312
|
||||
msgid "The translation domain used by gettext"
|
||||
msgstr "Домен перекладу, що використовується gettext"
|
||||
|
||||
#: gtk/gtkbuilder.c:325
|
||||
#: gtk/gtkbuilder.c:323
|
||||
msgid "Current object"
|
||||
msgstr "Поточний об'єкт"
|
||||
|
||||
#: gtk/gtkbuilder.c:326
|
||||
#: gtk/gtkbuilder.c:324
|
||||
msgid "The object the builder is evaluating for"
|
||||
msgstr "Об'єкт для оцінки збиральником"
|
||||
|
||||
#: gtk/gtkbuilder.c:337 gtk/gtkshortcutcontroller.c:551
|
||||
#: gtk/gtkbuilder.c:335 gtk/gtkshortcutcontroller.c:550
|
||||
msgid "Scope"
|
||||
msgstr "Область"
|
||||
|
||||
#: gtk/gtkbuilder.c:338
|
||||
#: gtk/gtkbuilder.c:336
|
||||
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:640
|
||||
#: gtk/gtkscrolledwindow.c:641
|
||||
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:683
|
||||
#: gtk/gtkcellrenderercombo.c:136 gtk/gtkfilterlistmodel.c:416
|
||||
#: gtk/gtkflattenlistmodel.c:438 gtk/gtkmaplistmodel.c:404
|
||||
#: gtk/gtkshortcutcontroller.c:539 gtk/gtkslicelistmodel.c:287
|
||||
#: gtk/gtksortlistmodel.c:394 gtk/gtktreelistmodel.c:716
|
||||
#: gtk/gtkshortcutcontroller.c:538 gtk/gtkslicelistmodel.c:287
|
||||
#: gtk/gtksortlistmodel.c:338 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:752
|
||||
#: gtk/gtkcellrenderertext.c:269 gtk/gtkentry.c:890 gtk/gtklabel.c:753
|
||||
#: gtk/gtktext.c:894
|
||||
msgid "Attributes"
|
||||
msgstr "Атрибути"
|
||||
@@ -1536,7 +1536,7 @@ msgstr ""
|
||||
"під час відтворення тексту. Якщо ви не розумієте цей параметр, то, напевно, "
|
||||
"він вам не потрібний."
|
||||
|
||||
#: gtk/gtkcellrenderertext.c:446 gtk/gtklabel.c:872 gtk/gtkprogressbar.c:246
|
||||
#: gtk/gtkcellrenderertext.c:446 gtk/gtklabel.c:873 gtk/gtkprogressbar.c:246
|
||||
msgid "Ellipsize"
|
||||
msgstr "Овал"
|
||||
|
||||
@@ -1549,15 +1549,15 @@ msgstr ""
|
||||
"для показу всього рядка"
|
||||
|
||||
#: gtk/gtkcellrenderertext.c:463 gtk/gtkfilechooserbutton.c:524
|
||||
#: gtk/gtklabel.c:890
|
||||
#: gtk/gtklabel.c:891
|
||||
msgid "Width In Characters"
|
||||
msgstr "Ширина у символах"
|
||||
|
||||
#: gtk/gtkcellrenderertext.c:464 gtk/gtklabel.c:891
|
||||
#: gtk/gtkcellrenderertext.c:464 gtk/gtklabel.c:892
|
||||
msgid "The desired width of the label, in characters"
|
||||
msgstr "Бажана ширина, у символах"
|
||||
|
||||
#: gtk/gtkcellrenderertext.c:483 gtk/gtklabel.c:924
|
||||
#: gtk/gtkcellrenderertext.c:483 gtk/gtklabel.c:925
|
||||
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:583
|
||||
#: gtk/gtkcellview.c:215 gtk/gtkentrycompletion.c:439 gtk/gtkiconview.c:584
|
||||
#: gtk/gtktreepopover.c:213 gtk/gtktreeviewcolumn.c:423
|
||||
msgid "Cell Area"
|
||||
msgstr "Ділянка комірки"
|
||||
|
||||
#: gtk/gtkcellview.c:216 gtk/gtkentrycompletion.c:440 gtk/gtkiconview.c:584
|
||||
#: gtk/gtkcellview.c:216 gtk/gtkentrycompletion.c:440 gtk/gtkiconview.c:585
|
||||
#: 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:835 gtk/gtklistbox.c:3448
|
||||
#: gtk/gtkcolorswatch.c:485 gtk/gtklabel.c:836 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:789
|
||||
#: gtk/gtkeditable.c:423 gtk/gtklabel.c:790
|
||||
msgid "X align"
|
||||
msgstr "Вирівнювання за X"
|
||||
|
||||
#: gtk/gtkeditable.c:424 gtk/gtklabel.c:790
|
||||
#: gtk/gtkeditable.c:424 gtk/gtklabel.c:791
|
||||
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:954 gtk/gtkpasswordentry.c:418
|
||||
#: gtk/gtkentry.c:928 gtk/gtklabel.c:955 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:401
|
||||
#: gtk/gtkentrycompletion.c:354 gtk/gtkiconview.c:402
|
||||
msgid "Text column"
|
||||
msgstr "Текстовий стовпчик"
|
||||
|
||||
@@ -2741,11 +2741,11 @@ msgstr "Чи розширювач був відкритий для показу
|
||||
msgid "Text of the expander’s label"
|
||||
msgstr "Текст мітки розгортання"
|
||||
|
||||
#: gtk/gtkexpander.c:336 gtk/gtklabel.c:759 gtk/gtkmodelbutton.c:1149
|
||||
#: gtk/gtkexpander.c:336 gtk/gtklabel.c:760 gtk/gtkmodelbutton.c:1149
|
||||
msgid "Use markup"
|
||||
msgstr "Використовувати розмітку"
|
||||
|
||||
#: gtk/gtkexpander.c:337 gtk/gtklabel.c:760
|
||||
#: gtk/gtkexpander.c:337 gtk/gtklabel.c:761
|
||||
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/gtkfilterlistmodel.c:659
|
||||
#: gtk/gtkfilechooser.c:160
|
||||
msgid "Filter"
|
||||
msgstr "Фільтр"
|
||||
|
||||
@@ -2854,24 +2854,27 @@ msgstr "Підзаголовок"
|
||||
msgid "The human-readable name for this 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:392
|
||||
msgid "has filter"
|
||||
msgstr "має фільтр"
|
||||
|
||||
#: gtk/gtkfilterlistmodel.c:671 gtk/gtkflattenlistmodel.c:426
|
||||
#: gtk/gtkfilterlistmodel.c:393
|
||||
msgid "If a filter is set for this model"
|
||||
msgstr "Чи встановлено фільтр для цієї моделі"
|
||||
|
||||
#: gtk/gtkfilterlistmodel.c:404 gtk/gtkflattenlistmodel.c:426
|
||||
#: gtk/gtkmaplistmodel.c:392 gtk/gtkpropertylookuplistmodel.c:376
|
||||
#: gtk/gtkslicelistmodel.c:275 gtk/gtksortlistmodel.c:382
|
||||
#: gtk/gtkslicelistmodel.c:275 gtk/gtksortlistmodel.c:326
|
||||
msgid "Item type"
|
||||
msgstr "Тип запису"
|
||||
|
||||
#: gtk/gtkfilterlistmodel.c:672 gtk/gtkflattenlistmodel.c:427
|
||||
#: gtk/gtkfilterlistmodel.c:405 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:684
|
||||
#: gtk/gtkfilterlistmodel.c:417
|
||||
msgid "The model being filtered"
|
||||
msgstr "Модель, яка фільтрується"
|
||||
|
||||
@@ -2887,22 +2890,22 @@ msgstr "Перетворення дочірнього об'єкта із фік
|
||||
msgid "The model being flattened"
|
||||
msgstr "Модель, яка сплощується"
|
||||
|
||||
#: gtk/gtkflowbox.c:3578 gtk/gtkiconview.c:368 gtk/gtklistbox.c:488
|
||||
#: gtk/gtkflowbox.c:3578 gtk/gtkiconview.c:369 gtk/gtklistbox.c:488
|
||||
#: gtk/gtktreeselection.c:140
|
||||
msgid "Selection mode"
|
||||
msgstr "Режим виділення"
|
||||
|
||||
#: gtk/gtkflowbox.c:3579 gtk/gtkiconview.c:369 gtk/gtklistbox.c:489
|
||||
#: gtk/gtkflowbox.c:3579 gtk/gtkiconview.c:370 gtk/gtklistbox.c:489
|
||||
msgid "The selection mode"
|
||||
msgstr "Режим виділення"
|
||||
|
||||
#: gtk/gtkflowbox.c:3592 gtk/gtkiconview.c:597 gtk/gtklistbox.c:496
|
||||
#: gtk/gtktreeview.c:1203
|
||||
#: gtk/gtkflowbox.c:3592 gtk/gtkiconview.c:598 gtk/gtklistbox.c:496
|
||||
#: gtk/gtktreeview.c:1205
|
||||
msgid "Activate on Single Click"
|
||||
msgstr "Активувати одиночним клацанням"
|
||||
|
||||
#: gtk/gtkflowbox.c:3593 gtk/gtkiconview.c:598 gtk/gtklistbox.c:497
|
||||
#: gtk/gtktreeview.c:1204
|
||||
#: gtk/gtkflowbox.c:3593 gtk/gtkiconview.c:599 gtk/gtklistbox.c:497
|
||||
#: gtk/gtktreeview.c:1206
|
||||
msgid "Activate row on a single click"
|
||||
msgstr "Активувати рядок одиночним клацанням"
|
||||
|
||||
@@ -3014,11 +3017,11 @@ msgstr "Параметри шрифту у форматі рядка"
|
||||
msgid "Language for which features have been selected"
|
||||
msgstr "Мова, для якої були вибрані параметри"
|
||||
|
||||
#: gtk/gtkfontchooserwidget.c:664
|
||||
#: gtk/gtkfontchooserwidget.c:740
|
||||
msgid "The tweak action"
|
||||
msgstr "Дія коригування"
|
||||
|
||||
#: gtk/gtkfontchooserwidget.c:665
|
||||
#: gtk/gtkfontchooserwidget.c:741
|
||||
msgid "The toggle action to switch to the tweak page"
|
||||
msgstr "Увімкнути дію для перемикання сторінки коригування"
|
||||
|
||||
@@ -3249,6 +3252,7 @@ msgid "Icon name"
|
||||
msgstr "Назва піктограми"
|
||||
|
||||
#: gtk/gtkicontheme.c:3588
|
||||
#| msgid "The icon name choosen during lookup"
|
||||
msgid "The icon name chosen during lookup"
|
||||
msgstr "Назва піктограми, яку вибрано під час пошуку"
|
||||
|
||||
@@ -3260,112 +3264,112 @@ msgstr "Є символічною"
|
||||
msgid "If the icon is symbolic"
|
||||
msgstr "Чи є піктограма символічною"
|
||||
|
||||
#: gtk/gtkiconview.c:385
|
||||
#: gtk/gtkiconview.c:386
|
||||
msgid "Pixbuf column"
|
||||
msgstr "Стовпчик pixbuf"
|
||||
|
||||
#: gtk/gtkiconview.c:386
|
||||
#: gtk/gtkiconview.c:387
|
||||
msgid "Model column used to retrieve the icon pixbuf from"
|
||||
msgstr ""
|
||||
"Модель стовпця, що використовується для отримання зображення (pixbuf) значка"
|
||||
|
||||
#: gtk/gtkiconview.c:402
|
||||
#: gtk/gtkiconview.c:403
|
||||
msgid "Model column used to retrieve the text from"
|
||||
msgstr "Модель стовпчика, що використовується для отримання з неї тексту"
|
||||
|
||||
#: gtk/gtkiconview.c:419
|
||||
#: gtk/gtkiconview.c:420
|
||||
msgid "Markup column"
|
||||
msgstr "Розмітка стовпчика"
|
||||
|
||||
#: gtk/gtkiconview.c:420
|
||||
#: gtk/gtkiconview.c:421
|
||||
msgid "Model column used to retrieve the text if using Pango markup"
|
||||
msgstr ""
|
||||
"Модель стовпчика, що використовується для тримання з неї тексту, якщо "
|
||||
"використовується розмітка pango"
|
||||
|
||||
#: gtk/gtkiconview.c:427
|
||||
#: gtk/gtkiconview.c:428
|
||||
msgid "Icon View Model"
|
||||
msgstr "Модель Icon View"
|
||||
|
||||
#: gtk/gtkiconview.c:428
|
||||
#: gtk/gtkiconview.c:429
|
||||
msgid "The model for the icon view"
|
||||
msgstr "Модель для перегляду у вигляді значків"
|
||||
|
||||
#: gtk/gtkiconview.c:442
|
||||
#: gtk/gtkiconview.c:443
|
||||
msgid "Number of columns"
|
||||
msgstr "Кількість стовпчиків"
|
||||
|
||||
#: gtk/gtkiconview.c:443
|
||||
#: gtk/gtkiconview.c:444
|
||||
msgid "Number of columns to display"
|
||||
msgstr "Кількість стовпчиків, які показуються"
|
||||
|
||||
#: gtk/gtkiconview.c:458
|
||||
#: gtk/gtkiconview.c:459
|
||||
msgid "Width for each item"
|
||||
msgstr "Віджет для кожного елемента"
|
||||
|
||||
#: gtk/gtkiconview.c:459
|
||||
#: gtk/gtkiconview.c:460
|
||||
msgid "The width used for each item"
|
||||
msgstr "Ширина, що використовується для кожного елемента"
|
||||
|
||||
#: gtk/gtkiconview.c:473
|
||||
#: gtk/gtkiconview.c:474
|
||||
msgid "Space which is inserted between cells of an item"
|
||||
msgstr "Простір, що вставляється між комірками елемента"
|
||||
|
||||
#: gtk/gtkiconview.c:486
|
||||
#: gtk/gtkiconview.c:487
|
||||
msgid "Row Spacing"
|
||||
msgstr "Міжрядковий інтервал"
|
||||
|
||||
#: gtk/gtkiconview.c:487
|
||||
#: gtk/gtkiconview.c:488
|
||||
msgid "Space which is inserted between grid rows"
|
||||
msgstr "Простір, що вставляється між рядками сітки"
|
||||
|
||||
#: gtk/gtkiconview.c:500
|
||||
#: gtk/gtkiconview.c:501
|
||||
msgid "Column Spacing"
|
||||
msgstr "Інтервал між стовпчиками"
|
||||
|
||||
#: gtk/gtkiconview.c:501
|
||||
#: gtk/gtkiconview.c:502
|
||||
msgid "Space which is inserted between grid columns"
|
||||
msgstr "Простір, що вставляється між стовпчиками сітки"
|
||||
|
||||
#: gtk/gtkiconview.c:514
|
||||
#: gtk/gtkiconview.c:515
|
||||
msgid "Margin"
|
||||
msgstr "Відступ"
|
||||
|
||||
#: gtk/gtkiconview.c:515
|
||||
#: gtk/gtkiconview.c:516
|
||||
msgid "Space which is inserted at the edges of the icon view"
|
||||
msgstr "Простір, що вставляється на краях перегляду піктограми"
|
||||
|
||||
#: gtk/gtkiconview.c:528
|
||||
#: gtk/gtkiconview.c:529
|
||||
msgid "Item Orientation"
|
||||
msgstr "Орієнтація пункту "
|
||||
|
||||
#: gtk/gtkiconview.c:529
|
||||
#: gtk/gtkiconview.c:530
|
||||
msgid ""
|
||||
"How the text and icon of each item are positioned relative to each other"
|
||||
msgstr ""
|
||||
"Як текст та значки кожного елемента розташовуються один відносно іншого"
|
||||
|
||||
#: gtk/gtkiconview.c:543 gtk/gtktreeview.c:1069 gtk/gtktreeviewcolumn.c:379
|
||||
#: gtk/gtkiconview.c:544 gtk/gtktreeview.c:1071 gtk/gtktreeviewcolumn.c:379
|
||||
msgid "Reorderable"
|
||||
msgstr "Дозволено перестановку"
|
||||
|
||||
#: gtk/gtkiconview.c:544 gtk/gtktreeview.c:1070
|
||||
#: gtk/gtkiconview.c:545 gtk/gtktreeview.c:1072
|
||||
msgid "View is reorderable"
|
||||
msgstr "Перегляд можна перегрупувати"
|
||||
|
||||
#: gtk/gtkiconview.c:551 gtk/gtktreeview.c:1189
|
||||
#: gtk/gtkiconview.c:552 gtk/gtktreeview.c:1191
|
||||
msgid "Tooltip Column"
|
||||
msgstr "Стовпчик підказки"
|
||||
|
||||
#: gtk/gtkiconview.c:552
|
||||
#: gtk/gtkiconview.c:553
|
||||
msgid "The column in the model containing the tooltip texts for the items"
|
||||
msgstr "Стовпчик у моделі, що містить текстову підказку для елементів"
|
||||
|
||||
#: gtk/gtkiconview.c:567
|
||||
#: gtk/gtkiconview.c:568
|
||||
msgid "Item Padding"
|
||||
msgstr "Доповнення елемента"
|
||||
|
||||
#: gtk/gtkiconview.c:568
|
||||
#: gtk/gtkiconview.c:569
|
||||
msgid "Padding around icon view items"
|
||||
msgstr "Доповнення навколо значків"
|
||||
|
||||
@@ -3445,19 +3449,19 @@ msgstr "Чи потрібно додавати стандартну кнопку
|
||||
msgid "Controls whether the info bar shows its contents or not"
|
||||
msgstr "Керує тим, чи буде показано вміст інформаційної панелі"
|
||||
|
||||
#: gtk/gtklabel.c:746
|
||||
#: gtk/gtklabel.c:747
|
||||
msgid "The text of the label"
|
||||
msgstr "Текст позначки"
|
||||
|
||||
#: gtk/gtklabel.c:753
|
||||
#: gtk/gtklabel.c:754
|
||||
msgid "A list of style attributes to apply to the text of the label"
|
||||
msgstr "Список стильових ознак для застосування до тексту позначки"
|
||||
|
||||
#: gtk/gtklabel.c:773 gtk/gtktexttag.c:386 gtk/gtktextview.c:877
|
||||
#: gtk/gtklabel.c:774 gtk/gtktexttag.c:386 gtk/gtktextview.c:877
|
||||
msgid "Justification"
|
||||
msgstr "Вирівнювання"
|
||||
|
||||
#: gtk/gtklabel.c:774
|
||||
#: gtk/gtklabel.c:775
|
||||
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 "
|
||||
@@ -3467,80 +3471,80 @@ msgstr ""
|
||||
"вирівнювання мітки всередині вказаного для неї місця. З цього питання див. "
|
||||
"GtkLabel::xalign"
|
||||
|
||||
#: gtk/gtklabel.c:805
|
||||
#: gtk/gtklabel.c:806
|
||||
msgid "Y align"
|
||||
msgstr "Вирівнювання за Y"
|
||||
|
||||
#: gtk/gtklabel.c:806
|
||||
#: gtk/gtklabel.c:807
|
||||
msgid "The vertical alignment, from 0 (top) to 1 (bottom)"
|
||||
msgstr "Вертикальне вирівнювання, від 0 (вгору) до 1 (вниз)"
|
||||
|
||||
#: gtk/gtklabel.c:813
|
||||
#: gtk/gtklabel.c:814
|
||||
msgid "Line wrap"
|
||||
msgstr "Перенос рядків"
|
||||
|
||||
#: gtk/gtklabel.c:814
|
||||
#: gtk/gtklabel.c:815
|
||||
msgid "If set, wrap lines if the text becomes too wide"
|
||||
msgstr "Якщо встановлено, занадто довгі рядки переносяться"
|
||||
|
||||
#: gtk/gtklabel.c:827
|
||||
#: gtk/gtklabel.c:828
|
||||
msgid "Line wrap mode"
|
||||
msgstr "Режим переносу рядків"
|
||||
|
||||
#: gtk/gtklabel.c:828
|
||||
#: gtk/gtklabel.c:829
|
||||
msgid "If wrap is set, controls how linewrapping is done"
|
||||
msgstr ""
|
||||
"Якщо встановлено перенос рядків, контролює як виконувати перенос рядків"
|
||||
|
||||
#: gtk/gtklabel.c:836
|
||||
#: gtk/gtklabel.c:837
|
||||
msgid "Whether the label text can be selected with the mouse"
|
||||
msgstr "Чи може текст позначки бути виділений використовуючи мишу"
|
||||
|
||||
#: gtk/gtklabel.c:842
|
||||
#: gtk/gtklabel.c:843
|
||||
msgid "Mnemonic key"
|
||||
msgstr "Мнемонічна клавіша"
|
||||
|
||||
#: gtk/gtklabel.c:843
|
||||
#: gtk/gtklabel.c:844
|
||||
msgid "The mnemonic accelerator key for this label"
|
||||
msgstr "Мнемонічна клавіша-прискорювач для цієї позначки"
|
||||
|
||||
#: gtk/gtklabel.c:850
|
||||
#: gtk/gtklabel.c:851
|
||||
msgid "Mnemonic widget"
|
||||
msgstr "Мнемонічний віджет"
|
||||
|
||||
#: gtk/gtklabel.c:851
|
||||
#: gtk/gtklabel.c:852
|
||||
msgid "The widget to be activated when the label’s mnemonic key is pressed"
|
||||
msgstr ""
|
||||
"Віджет, який буде активовано під час натиснення мнемонічної клавіші позначки"
|
||||
|
||||
#: gtk/gtklabel.c:873
|
||||
#: gtk/gtklabel.c:874
|
||||
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:907
|
||||
#: gtk/gtklabel.c:908
|
||||
msgid "Single Line Mode"
|
||||
msgstr "Режим одного рядка"
|
||||
|
||||
#: gtk/gtklabel.c:908
|
||||
#: gtk/gtklabel.c:909
|
||||
msgid "Whether the label is in single line mode"
|
||||
msgstr "Чи знаходиться рядок у режимі одного рядка"
|
||||
|
||||
#: gtk/gtklabel.c:925
|
||||
#: gtk/gtklabel.c:926
|
||||
msgid "The desired maximum width of the label, in characters"
|
||||
msgstr "Бажана максимальна ширина ярлика, у символах"
|
||||
|
||||
#: gtk/gtklabel.c:940
|
||||
#: gtk/gtklabel.c:941
|
||||
msgid "Number of lines"
|
||||
msgstr "Кількість ліній"
|
||||
|
||||
#: gtk/gtklabel.c:941
|
||||
#: gtk/gtklabel.c:942
|
||||
msgid "The desired number of lines, when ellipsizing a wrapping label"
|
||||
msgstr "Число рядків при скороченні мітки з використанням трьох крапок"
|
||||
|
||||
#: gtk/gtklabel.c:955 gtk/gtktext.c:941 gtk/gtktextview.c:1079
|
||||
#: gtk/gtklabel.c:956 gtk/gtktext.c:941 gtk/gtktextview.c:1079
|
||||
msgid "Menu model to append to the context menu"
|
||||
msgstr "Модель меню для долучення до контекстного меню"
|
||||
|
||||
@@ -3815,7 +3819,7 @@ msgstr "Гучність"
|
||||
msgid "Volume of the audio stream."
|
||||
msgstr "Гучність відтворення потоку звукових даних."
|
||||
|
||||
#: gtk/gtkmenubutton.c:370 gtk/gtkpopovermenubar.c:593 gtk/gtkpopovermenu.c:517
|
||||
#: gtk/gtkmenubutton.c:370 gtk/gtkpopovermenubar.c:595 gtk/gtkpopovermenu.c:518
|
||||
msgid "Menu model"
|
||||
msgstr "Модель меню"
|
||||
|
||||
@@ -4499,19 +4503,19 @@ msgstr "Мнемоніка видима"
|
||||
msgid "Whether mnemonics are currently visible in this popover"
|
||||
msgstr "Чи показано мнемоніку у цьому накладному меню"
|
||||
|
||||
#: gtk/gtkpopovermenubar.c:594
|
||||
#: gtk/gtkpopovermenubar.c:596
|
||||
msgid "The model from which the bar is made."
|
||||
msgstr "Модель, на основі якої створено панель."
|
||||
|
||||
#: gtk/gtkpopovermenu.c:509
|
||||
#: gtk/gtkpopovermenu.c:510
|
||||
msgid "Visible submenu"
|
||||
msgstr "Видиме підменю"
|
||||
|
||||
#: gtk/gtkpopovermenu.c:510
|
||||
#: gtk/gtkpopovermenu.c:511
|
||||
msgid "The name of the visible submenu"
|
||||
msgstr "Назва видимого підменю"
|
||||
|
||||
#: gtk/gtkpopovermenu.c:518
|
||||
#: gtk/gtkpopovermenu.c:519
|
||||
msgid "The model from which the menu is made."
|
||||
msgstr "Модель, для якої створено меню."
|
||||
|
||||
@@ -5050,105 +5054,105 @@ msgstr "Політика вертикальної прокрутки"
|
||||
msgid "The GtkAdjustment that contains the current value of this scrollbar"
|
||||
msgstr "Об'єкт GtkAdjustment, що містить поточне значення цієї смужки гортання"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:602
|
||||
#: gtk/gtkscrolledwindow.c:603
|
||||
msgid "Horizontal Adjustment"
|
||||
msgstr "Горизонтальне вирівнювання"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:603
|
||||
#: gtk/gtkscrolledwindow.c:604
|
||||
msgid "The GtkAdjustment for the horizontal position"
|
||||
msgstr "Об'єкт GtkAdjustment для горизонтальної позиції"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:609
|
||||
#: gtk/gtkscrolledwindow.c:610
|
||||
msgid "Vertical Adjustment"
|
||||
msgstr "Вертикальне вирівнювання"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:610
|
||||
#: gtk/gtkscrolledwindow.c:611
|
||||
msgid "The GtkAdjustment for the vertical position"
|
||||
msgstr "Об'єкт GtkAdjustment для вертикальної позиції"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:616
|
||||
#: gtk/gtkscrolledwindow.c:617
|
||||
msgid "Horizontal Scrollbar Policy"
|
||||
msgstr "Правило горизонтальної прокрутки"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:617
|
||||
#: gtk/gtkscrolledwindow.c:618
|
||||
msgid "When the horizontal scrollbar is displayed"
|
||||
msgstr "Коли показано горизонтальну панель прокрутки"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:624
|
||||
#: gtk/gtkscrolledwindow.c:625
|
||||
msgid "Vertical Scrollbar Policy"
|
||||
msgstr "Правило вертикальної прокрутки"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:625
|
||||
#: gtk/gtkscrolledwindow.c:626
|
||||
msgid "When the vertical scrollbar is displayed"
|
||||
msgstr "Коли показано вертикальну панель прокрутки"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:632
|
||||
#: gtk/gtkscrolledwindow.c:633
|
||||
msgid "Window Placement"
|
||||
msgstr "Розміщення вікна"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:633
|
||||
#: gtk/gtkscrolledwindow.c:634
|
||||
msgid "Where the contents are located with respect to the scrollbars."
|
||||
msgstr "Чи розташовувати вміст у відповідності зі смугами гортання."
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:641
|
||||
#: gtk/gtkscrolledwindow.c:642
|
||||
msgid "Whether to draw a frame around the contents"
|
||||
msgstr "Чи слід малювати рамку навколо вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:652
|
||||
#: gtk/gtkscrolledwindow.c:653
|
||||
msgid "Minimum Content Width"
|
||||
msgstr "Мінімальна ширина вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:653
|
||||
#: gtk/gtkscrolledwindow.c:654
|
||||
msgid "The minimum width that the scrolled window will allocate to its content"
|
||||
msgstr "Мінімальна ширина, яку вікна прокрутки виділять з його вмістом"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:664
|
||||
#: gtk/gtkscrolledwindow.c:665
|
||||
msgid "Minimum Content Height"
|
||||
msgstr "Мінімальна висота вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:665
|
||||
#: gtk/gtkscrolledwindow.c:666
|
||||
msgid ""
|
||||
"The minimum height that the scrolled window will allocate to its content"
|
||||
msgstr "Мінімальна висота, яку вікна прокрутки виділять з його вмістом"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:677
|
||||
#: gtk/gtkscrolledwindow.c:678
|
||||
msgid "Kinetic Scrolling"
|
||||
msgstr "Кінетичне прокручування"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:678
|
||||
#: gtk/gtkscrolledwindow.c:679
|
||||
msgid "Kinetic scrolling mode."
|
||||
msgstr "Режим кінетичного прокручування."
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:695
|
||||
#: gtk/gtkscrolledwindow.c:696
|
||||
msgid "Overlay Scrolling"
|
||||
msgstr "Накладні смуги гортання"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:696
|
||||
#: gtk/gtkscrolledwindow.c:697
|
||||
msgid "Overlay scrolling mode"
|
||||
msgstr "Режим накладних смуг гортання"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:707
|
||||
#: gtk/gtkscrolledwindow.c:708
|
||||
msgid "Maximum Content Width"
|
||||
msgstr "Максимальна ширина вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:708
|
||||
#: gtk/gtkscrolledwindow.c:709
|
||||
msgid "The maximum width that the scrolled window will allocate to its content"
|
||||
msgstr "Максимальна ширина, яку вікна зі смужками гортання матимуть для вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:719
|
||||
#: gtk/gtkscrolledwindow.c:720
|
||||
msgid "Maximum Content Height"
|
||||
msgstr "Максимальна висота вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:720
|
||||
#: gtk/gtkscrolledwindow.c:721
|
||||
msgid ""
|
||||
"The maximum height that the scrolled window will allocate to its content"
|
||||
msgstr "Максимальна висота, яку вікна зі смужками гортання матимуть для вмісту"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:735 gtk/gtkscrolledwindow.c:736
|
||||
#: gtk/gtkscrolledwindow.c:736 gtk/gtkscrolledwindow.c:737
|
||||
msgid "Propagate Natural Width"
|
||||
msgstr "Передавати природну ширину"
|
||||
|
||||
#: gtk/gtkscrolledwindow.c:751 gtk/gtkscrolledwindow.c:752
|
||||
#: gtk/gtkscrolledwindow.c:752 gtk/gtkscrolledwindow.c:753
|
||||
msgid "Propagate Natural Height"
|
||||
msgstr "Передавати природну висоту"
|
||||
|
||||
@@ -5587,19 +5591,19 @@ msgstr "Чи показувати курсор у тексті"
|
||||
msgid "Whether to use overlay scrollbars"
|
||||
msgstr "Чи використовувати накладання смужок гортання"
|
||||
|
||||
#: gtk/gtkshortcutaction.c:942
|
||||
#: gtk/gtkshortcutaction.c:935
|
||||
msgid "Signal Name"
|
||||
msgstr "Назва сигналу"
|
||||
|
||||
#: gtk/gtkshortcutaction.c:943
|
||||
#: gtk/gtkshortcutaction.c:936
|
||||
msgid "The name of the signal to emit"
|
||||
msgstr "Назва сигналу, який слід надіслати"
|
||||
|
||||
#: gtk/gtkshortcutaction.c:1181 gtk/gtkshortcutsshortcut.c:718
|
||||
#: gtk/gtkshortcutaction.c:1174 gtk/gtkshortcutsshortcut.c:718
|
||||
msgid "Action Name"
|
||||
msgstr "Назва дії"
|
||||
|
||||
#: gtk/gtkshortcutaction.c:1182
|
||||
#: gtk/gtkshortcutaction.c:1175
|
||||
msgid "The name of the action to activate"
|
||||
msgstr "Назва дії для активації"
|
||||
|
||||
@@ -5623,21 +5627,21 @@ msgstr "Перемикач"
|
||||
msgid "The trigger for this shortcut"
|
||||
msgstr "Перемикач для цього скорочення"
|
||||
|
||||
#: gtk/gtkshortcutcontroller.c:526
|
||||
#: gtk/gtkshortcutcontroller.c:525
|
||||
msgid "Mnemonic modifers"
|
||||
msgstr "Модифікатори мнемоніки"
|
||||
|
||||
#: gtk/gtkshortcutcontroller.c:527
|
||||
#: gtk/gtkshortcutcontroller.c:526
|
||||
msgid "The modifiers to be pressed to allow mnemonics activation"
|
||||
msgstr ""
|
||||
"Клавіші-модифікатори, які має бути натиснуто, щоб уможливити активацію "
|
||||
"мнемоніки"
|
||||
|
||||
#: gtk/gtkshortcutcontroller.c:540
|
||||
#: gtk/gtkshortcutcontroller.c:539
|
||||
msgid "A list model to take shortcuts from"
|
||||
msgstr "Модель списку, з якої слід брати скорочення"
|
||||
|
||||
#: gtk/gtkshortcutcontroller.c:552
|
||||
#: gtk/gtkshortcutcontroller.c:551
|
||||
msgid "What scope the shortcuts will be handled in"
|
||||
msgstr "Область, у якій оброблятимуться скорочення"
|
||||
|
||||
@@ -5819,21 +5823,19 @@ msgstr "Зсув зрізу"
|
||||
msgid "Maximum size of slice"
|
||||
msgstr "Максимальний розмір зрізу"
|
||||
|
||||
#: gtk/gtksortlistmodel.c:370
|
||||
#| msgid "Sort order"
|
||||
msgid "Sorter"
|
||||
msgstr "Сортувальник"
|
||||
#: gtk/gtksortlistmodel.c:314
|
||||
msgid "has sort"
|
||||
msgstr "має упорядкування"
|
||||
|
||||
#: gtk/gtksortlistmodel.c:371
|
||||
#| msgid "The trigger for this shortcut"
|
||||
msgid "The sorter for this model"
|
||||
msgstr "Сортувальник для цієї моделі"
|
||||
#: gtk/gtksortlistmodel.c:315
|
||||
msgid "If a sort function is set for this model"
|
||||
msgstr "Чи встановлено функцію упорядкування для цієї моделі"
|
||||
|
||||
#: gtk/gtksortlistmodel.c:383
|
||||
#: gtk/gtksortlistmodel.c:327
|
||||
msgid "The type of items of this list"
|
||||
msgstr "Тип пунктів у цьому списку"
|
||||
|
||||
#: gtk/gtksortlistmodel.c:395
|
||||
#: gtk/gtksortlistmodel.c:339
|
||||
msgid "The model being sorted"
|
||||
msgstr "Модель, яка зберігається"
|
||||
|
||||
@@ -6748,126 +6750,126 @@ msgstr "модель"
|
||||
msgid "The model for the popover"
|
||||
msgstr "Модель для накладного меню"
|
||||
|
||||
#: gtk/gtktreeview.c:1041
|
||||
#: gtk/gtktreeview.c:1043
|
||||
msgid "TreeView Model"
|
||||
msgstr "Модель TreeView"
|
||||
|
||||
#: gtk/gtktreeview.c:1042
|
||||
#: gtk/gtktreeview.c:1044
|
||||
msgid "The model for the tree view"
|
||||
msgstr "Модель для перегляду у вигляді дерева"
|
||||
|
||||
#: gtk/gtktreeview.c:1048
|
||||
#: gtk/gtktreeview.c:1050
|
||||
msgid "Headers Visible"
|
||||
msgstr "Заголовки видимі"
|
||||
|
||||
#: gtk/gtktreeview.c:1049
|
||||
#: gtk/gtktreeview.c:1051
|
||||
msgid "Show the column header buttons"
|
||||
msgstr "Показувати кнопки заголовків стовпчиків"
|
||||
|
||||
#: gtk/gtktreeview.c:1055
|
||||
#: gtk/gtktreeview.c:1057
|
||||
msgid "Headers Clickable"
|
||||
msgstr "Заголовки натискаються"
|
||||
|
||||
#: gtk/gtktreeview.c:1056
|
||||
#: gtk/gtktreeview.c:1058
|
||||
msgid "Column headers respond to click events"
|
||||
msgstr "Заголовки стовпчиків відповідають на події клацання"
|
||||
|
||||
#: gtk/gtktreeview.c:1062
|
||||
#: gtk/gtktreeview.c:1064
|
||||
msgid "Expander Column"
|
||||
msgstr "Колонка-розширювач"
|
||||
|
||||
#: gtk/gtktreeview.c:1063
|
||||
#: gtk/gtktreeview.c:1065
|
||||
msgid "Set the column for the expander column"
|
||||
msgstr "Встановити колонку для розширювача"
|
||||
|
||||
#: gtk/gtktreeview.c:1076
|
||||
#: gtk/gtktreeview.c:1078
|
||||
msgid "Enable Search"
|
||||
msgstr "Дозволено пошук"
|
||||
|
||||
#: gtk/gtktreeview.c:1077
|
||||
#: gtk/gtktreeview.c:1079
|
||||
msgid "View allows user to search through columns interactively"
|
||||
msgstr ""
|
||||
"Перегляд дозволяє користувачу виконувати пошук у стовпчиках в інтерактивному "
|
||||
"режимі"
|
||||
|
||||
#: gtk/gtktreeview.c:1083
|
||||
#: gtk/gtktreeview.c:1085
|
||||
msgid "Search Column"
|
||||
msgstr "Стовпчик пошуку"
|
||||
|
||||
#: gtk/gtktreeview.c:1084
|
||||
#: gtk/gtktreeview.c:1086
|
||||
msgid "Model column to search through during interactive search"
|
||||
msgstr ""
|
||||
"Стовпчик моделі, за яким слід виконати інтерактивний пошук в міру набору"
|
||||
|
||||
#: gtk/gtktreeview.c:1100
|
||||
#: gtk/gtktreeview.c:1102
|
||||
msgid "Fixed Height Mode"
|
||||
msgstr "Режим фіксованої висоти"
|
||||
|
||||
#: gtk/gtktreeview.c:1101
|
||||
#: gtk/gtktreeview.c:1103
|
||||
msgid "Speeds up GtkTreeView by assuming that all rows have the same height"
|
||||
msgstr "Прискорює GtkTreeView, вважаючи що всі рядки мають ту ж саму висоту"
|
||||
|
||||
#: gtk/gtktreeview.c:1118
|
||||
#: gtk/gtktreeview.c:1120
|
||||
msgid "Hover Selection"
|
||||
msgstr "Курсорне виділення"
|
||||
|
||||
#: gtk/gtktreeview.c:1119
|
||||
#: gtk/gtktreeview.c:1121
|
||||
msgid "Whether the selection should follow the pointer"
|
||||
msgstr "Чи повинно виділення слідувати за вказівником"
|
||||
|
||||
#: gtk/gtktreeview.c:1135
|
||||
#: gtk/gtktreeview.c:1137
|
||||
msgid "Hover Expand"
|
||||
msgstr "Курсорне розширення"
|
||||
|
||||
#: gtk/gtktreeview.c:1136
|
||||
#: gtk/gtktreeview.c:1138
|
||||
msgid ""
|
||||
"Whether rows should be expanded/collapsed when the pointer moves over them"
|
||||
msgstr ""
|
||||
"Чи повинні рядки розгортатись/згортатись при переміщенні над ними вказівника"
|
||||
|
||||
#: gtk/gtktreeview.c:1147
|
||||
#: gtk/gtktreeview.c:1149
|
||||
msgid "Show Expanders"
|
||||
msgstr "Показувати розширювачі"
|
||||
|
||||
#: gtk/gtktreeview.c:1148
|
||||
#: gtk/gtktreeview.c:1150
|
||||
msgid "View has expanders"
|
||||
msgstr "Віджет містить розширювачі"
|
||||
|
||||
#: gtk/gtktreeview.c:1159
|
||||
#: gtk/gtktreeview.c:1161
|
||||
msgid "Level Indentation"
|
||||
msgstr "Вирівнювання позначок"
|
||||
|
||||
#: gtk/gtktreeview.c:1160
|
||||
#: gtk/gtktreeview.c:1162
|
||||
msgid "Extra indentation for each level"
|
||||
msgstr "Додаткове вирівнювання для кожного рівня"
|
||||
|
||||
#: gtk/gtktreeview.c:1167
|
||||
#: gtk/gtktreeview.c:1169
|
||||
msgid "Rubber Banding"
|
||||
msgstr "Гумова стрічка"
|
||||
|
||||
#: gtk/gtktreeview.c:1168
|
||||
#: gtk/gtktreeview.c:1170
|
||||
msgid ""
|
||||
"Whether to enable selection of multiple items by dragging the mouse pointer"
|
||||
msgstr ""
|
||||
"Чи дозволяти виділення кількох елементів перетягуванням вказівника миші"
|
||||
|
||||
#: gtk/gtktreeview.c:1174
|
||||
#: gtk/gtktreeview.c:1176
|
||||
msgid "Enable Grid Lines"
|
||||
msgstr "Увімкнути лінії сітки"
|
||||
|
||||
#: gtk/gtktreeview.c:1175
|
||||
#: gtk/gtktreeview.c:1177
|
||||
msgid "Whether grid lines should be drawn in the tree view"
|
||||
msgstr "Чи слід показувати лінії ґраток у віджеті"
|
||||
|
||||
#: gtk/gtktreeview.c:1182
|
||||
#: gtk/gtktreeview.c:1184
|
||||
msgid "Enable Tree Lines"
|
||||
msgstr "Увімкнути лінії рівня вкладення"
|
||||
|
||||
#: gtk/gtktreeview.c:1183
|
||||
#: gtk/gtktreeview.c:1185
|
||||
msgid "Whether tree lines should be drawn in the tree view"
|
||||
msgstr "Чи слід показувати лінії рівня вкладення у віджеті"
|
||||
|
||||
#: gtk/gtktreeview.c:1190
|
||||
#: gtk/gtktreeview.c:1192
|
||||
msgid "The column in the model containing the tooltip texts for the rows"
|
||||
msgstr ""
|
||||
"Стовпчик у моделі джерела даних, що містить текстові підказки для рядків"
|
||||
@@ -7464,15 +7466,6 @@ 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 "Меню програм"
|
||||
|
||||
|
||||
@@ -488,8 +488,9 @@ const char *ui_file =
|
||||
"<interface>\n" \
|
||||
" <template class='GtkListItem'>\n" \
|
||||
" <property name='child'>\n" \
|
||||
" <object class='GtkCheckButton'>\n" \
|
||||
" <binding name='active'>\n" \
|
||||
" <object class='GtkImage'>\n" \
|
||||
" <property name='icon-name'>object-select-symbolic</property>\n" \
|
||||
" <binding name='visible'>\n" \
|
||||
" <closure type='gboolean' function='get_boolean'>\n" \
|
||||
" <lookup name='item' type='GtkTreeListRow'><lookup name='item'>GtkListItem</lookup></lookup>\n" \
|
||||
" <constant type='gchararray'>" attr "</constant>" \
|
||||
@@ -606,12 +607,13 @@ struct {
|
||||
#define G_FILE_ATTRIBUTE_RECENT_MODIFIED "recent::modified" /* int64 (time_t) */
|
||||
#endif
|
||||
|
||||
const char *factory_ui =
|
||||
const char *factory_ui_name =
|
||||
"<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
"<interface>\n"
|
||||
" <template class='GtkListItem'>\n"
|
||||
" <property name='child'>\n"
|
||||
" <object class='GtkLabel'>\n"
|
||||
" <property name='xalign'>0</property>\n"
|
||||
" <binding name='label'>\n"
|
||||
" <lookup name='title' type='GtkColumnViewColumn'>\n"
|
||||
" <lookup name='item'>GtkListItem</lookup>\n"
|
||||
@@ -622,6 +624,124 @@ const char *factory_ui =
|
||||
" </template>\n"
|
||||
"</interface>\n";
|
||||
|
||||
const char *factory_ui_visible =
|
||||
"<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
"<interface>\n"
|
||||
" <template class='GtkListItem'>\n"
|
||||
" <property name='child'>\n"
|
||||
" <object class='GtkCheckButton'>\n"
|
||||
" <signal name='toggled' handler='column_visible_toggled' object='GtkListItem'/>\n"
|
||||
" <binding name='active'>\n"
|
||||
" <lookup name='visible' type='GtkColumnViewColumn'>\n"
|
||||
" <lookup name='item'>GtkListItem</lookup>\n"
|
||||
" </lookup>\n"
|
||||
" </binding>\n"
|
||||
" </object>\n"
|
||||
" </property>\n"
|
||||
" </template>\n"
|
||||
"</interface>\n";
|
||||
|
||||
const char *factory_ui_resizable =
|
||||
"<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
"<interface>\n"
|
||||
" <template class='GtkListItem'>\n"
|
||||
" <property name='child'>\n"
|
||||
" <object class='GtkCheckButton'>\n"
|
||||
" <signal name='toggled' handler='column_resizable_toggled' object='GtkListItem'/>\n"
|
||||
" <binding name='active'>\n"
|
||||
" <lookup name='resizable' type='GtkColumnViewColumn'>\n"
|
||||
" <lookup name='item'>GtkListItem</lookup>\n"
|
||||
" </lookup>\n"
|
||||
" </binding>\n"
|
||||
" </object>\n"
|
||||
" </property>\n"
|
||||
" </template>\n"
|
||||
"</interface>\n";
|
||||
|
||||
const char *factory_ui_reorderable =
|
||||
"<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
"<interface>\n"
|
||||
" <template class='GtkListItem'>\n"
|
||||
" <property name='child'>\n"
|
||||
" <object class='GtkCheckButton'>\n"
|
||||
" <signal name='toggled' handler='column_reorderable_toggled' object='GtkListItem'/>\n"
|
||||
" <binding name='active'>\n"
|
||||
" <lookup name='reorderable' type='GtkColumnViewColumn'>\n"
|
||||
" <lookup name='item'>GtkListItem</lookup>\n"
|
||||
" </lookup>\n"
|
||||
" </binding>\n"
|
||||
" </object>\n"
|
||||
" </property>\n"
|
||||
" </template>\n"
|
||||
"</interface>\n";
|
||||
|
||||
const char *factory_ui_width =
|
||||
"<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
"<interface>\n"
|
||||
" <template class='GtkListItem'>\n"
|
||||
" <property name='child'>\n"
|
||||
" <object class='GtkSpinButton'>\n"
|
||||
" <property name='digits'>0</property>\n"
|
||||
" <property name='numeric'>1</property>\n"
|
||||
" <property name='adjustment'>\n"
|
||||
" <object class='GtkAdjustment'>\n"
|
||||
" <property name='lower'>-1</property>\n"
|
||||
" <property name='upper'>10000</property>\n"
|
||||
" <property name='step-increment'>1</property>\n"
|
||||
" <property name='page-increment'>10</property>\n"
|
||||
" </object>\n"
|
||||
" </property>\n"
|
||||
" <signal name='value-changed' handler='column_width_changed' object='GtkListItem'/>\n"
|
||||
" <binding name='value'>\n"
|
||||
" <closure type='gdouble' function='cast_to_double'>\n"
|
||||
" <lookup name='fixed-width' type='GtkColumnViewColumn'>\n"
|
||||
" <lookup name='item'>GtkListItem</lookup>\n"
|
||||
" </lookup>\n"
|
||||
" </closure>\n"
|
||||
" </binding>\n"
|
||||
" </object>\n"
|
||||
" </property>\n"
|
||||
" </template>\n"
|
||||
"</interface>\n";
|
||||
|
||||
static void
|
||||
column_visible_toggled (GtkListItem *item, GtkToggleButton *button)
|
||||
{
|
||||
GtkColumnViewColumn *column = gtk_list_item_get_item (item);
|
||||
|
||||
gtk_column_view_column_set_visible (column, gtk_toggle_button_get_active (button));
|
||||
}
|
||||
|
||||
static void
|
||||
column_resizable_toggled (GtkListItem *item, GtkToggleButton *button)
|
||||
{
|
||||
GtkColumnViewColumn *column = gtk_list_item_get_item (item);
|
||||
|
||||
gtk_column_view_column_set_resizable (column, gtk_toggle_button_get_active (button));
|
||||
}
|
||||
|
||||
static void
|
||||
column_reorderable_toggled (GtkListItem *item, GtkToggleButton *button)
|
||||
{
|
||||
GtkColumnViewColumn *column = gtk_list_item_get_item (item);
|
||||
|
||||
gtk_column_view_column_set_reorderable (column, gtk_toggle_button_get_active (button));
|
||||
}
|
||||
|
||||
static void
|
||||
column_width_changed (GtkListItem *item, GtkSpinButton *button)
|
||||
{
|
||||
GtkColumnViewColumn *column = gtk_list_item_get_item (item);
|
||||
|
||||
gtk_column_view_column_set_fixed_width (column, gtk_spin_button_get_value_as_int (button));
|
||||
}
|
||||
|
||||
static double
|
||||
cast_to_double (gpointer _this, int value)
|
||||
{
|
||||
return (double)value;
|
||||
}
|
||||
|
||||
static GtkBuilderScope *
|
||||
create_scope (void)
|
||||
{
|
||||
@@ -634,6 +754,11 @@ create_scope (void)
|
||||
ADD_SYMBOL (get_object);
|
||||
ADD_SYMBOL (get_string);
|
||||
ADD_SYMBOL (get_boolean);
|
||||
ADD_SYMBOL (column_visible_toggled);
|
||||
ADD_SYMBOL (column_resizable_toggled);
|
||||
ADD_SYMBOL (column_reorderable_toggled);
|
||||
ADD_SYMBOL (column_width_changed);
|
||||
ADD_SYMBOL (cast_to_double);
|
||||
|
||||
return scope;
|
||||
#undef ADD_SYMBOL
|
||||
@@ -668,11 +793,60 @@ search_changed_cb (GtkSearchEntry *entry,
|
||||
gtk_filter_changed (custom_filter, GTK_FILTER_CHANGE_DIFFERENT);
|
||||
}
|
||||
|
||||
static void
|
||||
move_column (GtkColumnView *list, gboolean down)
|
||||
{
|
||||
GListModel *columns;
|
||||
guint position;
|
||||
GtkColumnViewColumn *selected;
|
||||
GtkColumnView *view;
|
||||
|
||||
columns = gtk_column_view_get_model (list);
|
||||
position = gtk_single_selection_get_selected (GTK_SINGLE_SELECTION (columns));
|
||||
selected = gtk_single_selection_get_selected_item (GTK_SINGLE_SELECTION (columns));
|
||||
view = gtk_column_view_column_get_column_view (selected);
|
||||
|
||||
if (down && position + 1 < g_list_model_get_n_items (columns))
|
||||
position++;
|
||||
else if (!down && position > 0)
|
||||
position--;
|
||||
else
|
||||
return;
|
||||
|
||||
gtk_column_view_insert_column (view, position, selected);
|
||||
gtk_single_selection_set_selected (GTK_SINGLE_SELECTION (columns), position);
|
||||
gtk_widget_grab_focus (GTK_WIDGET (list));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
key_pressed_cb (GtkEventControllerKey *controller,
|
||||
guint keyval,
|
||||
guint keycode,
|
||||
GdkModifierType modifiers,
|
||||
GtkColumnView *list)
|
||||
{
|
||||
gboolean down;
|
||||
|
||||
if ((modifiers & GDK_CONTROL_MASK) == 0)
|
||||
return FALSE;
|
||||
|
||||
if (keyval == GDK_KEY_Down)
|
||||
down = TRUE;
|
||||
else if (keyval == GDK_KEY_Up)
|
||||
down = FALSE;
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
move_column (list, down);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GListModel *toplevels;
|
||||
GtkWidget *win, *hbox, *vbox, *sw, *view, *list, *search_entry, *statusbar;
|
||||
GtkWidget *win, *paned, *vbox, *sw, *view, *list, *search_entry, *statusbar;
|
||||
GListModel *dirmodel;
|
||||
GtkTreeListModel *tree;
|
||||
GtkFilterListModel *filter;
|
||||
@@ -683,17 +857,21 @@ main (int argc, char *argv[])
|
||||
GtkBuilderScope *scope;
|
||||
GtkBuilder *builder;
|
||||
GError *error = NULL;
|
||||
GtkColumnViewColumn *column;
|
||||
GListModel *model;
|
||||
GtkEventController *controller;
|
||||
|
||||
gtk_init ();
|
||||
|
||||
win = gtk_window_new ();
|
||||
gtk_window_set_default_size (GTK_WINDOW (win), 800, 600);
|
||||
|
||||
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
gtk_window_set_child (GTK_WINDOW (win), hbox);
|
||||
paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_paned_set_wide_handle (GTK_PANED (paned), TRUE);
|
||||
gtk_window_set_child (GTK_WINDOW (win), paned);
|
||||
|
||||
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_box_append (GTK_BOX (hbox), vbox);
|
||||
gtk_paned_set_start_child (GTK_PANED (paned), vbox);
|
||||
|
||||
search_entry = gtk_search_entry_new ();
|
||||
gtk_box_append (GTK_BOX (vbox), search_entry);
|
||||
@@ -750,13 +928,58 @@ main (int argc, char *argv[])
|
||||
g_object_unref (sort);
|
||||
g_object_unref (tree);
|
||||
|
||||
list = gtk_list_view_new_with_factory (
|
||||
gtk_builder_list_item_factory_new_from_bytes (scope, g_bytes_new_static (factory_ui, strlen (factory_ui))));
|
||||
gtk_list_view_set_model (GTK_LIST_VIEW (list), gtk_column_view_get_columns (GTK_COLUMN_VIEW (view)));
|
||||
gtk_box_append (GTK_BOX (hbox), list);
|
||||
list = gtk_column_view_new ();
|
||||
|
||||
column = gtk_column_view_column_new_with_factory ("Name",
|
||||
gtk_builder_list_item_factory_new_from_bytes (scope, g_bytes_new_static (factory_ui_name, strlen (factory_ui_name))));
|
||||
gtk_column_view_column_set_resizable (column, FALSE);
|
||||
gtk_column_view_column_set_reorderable (column, FALSE);
|
||||
gtk_column_view_append_column (GTK_COLUMN_VIEW (list), column);
|
||||
g_object_unref (column);
|
||||
|
||||
column = gtk_column_view_column_new_with_factory ("Visible",
|
||||
gtk_builder_list_item_factory_new_from_bytes (scope, g_bytes_new_static (factory_ui_visible, strlen (factory_ui_visible))));
|
||||
gtk_column_view_column_set_resizable (column, FALSE);
|
||||
gtk_column_view_column_set_reorderable (column, FALSE);
|
||||
gtk_column_view_append_column (GTK_COLUMN_VIEW (list), column);
|
||||
g_object_unref (column);
|
||||
|
||||
column = gtk_column_view_column_new_with_factory ("Resizable",
|
||||
gtk_builder_list_item_factory_new_from_bytes (scope, g_bytes_new_static (factory_ui_resizable, strlen (factory_ui_resizable))));
|
||||
gtk_column_view_column_set_resizable (column, FALSE);
|
||||
gtk_column_view_column_set_reorderable (column, FALSE);
|
||||
gtk_column_view_append_column (GTK_COLUMN_VIEW (list), column);
|
||||
g_object_unref (column);
|
||||
|
||||
column = gtk_column_view_column_new_with_factory ("Reorderable",
|
||||
gtk_builder_list_item_factory_new_from_bytes (scope, g_bytes_new_static (factory_ui_reorderable, strlen (factory_ui_reorderable))));
|
||||
gtk_column_view_column_set_resizable (column, FALSE);
|
||||
gtk_column_view_column_set_reorderable (column, FALSE);
|
||||
gtk_column_view_append_column (GTK_COLUMN_VIEW (list), column);
|
||||
g_object_unref (column);
|
||||
|
||||
column = gtk_column_view_column_new_with_factory ("Width",
|
||||
gtk_builder_list_item_factory_new_from_bytes (scope, g_bytes_new_static (factory_ui_width, strlen (factory_ui_width))));
|
||||
gtk_column_view_column_set_resizable (column, FALSE);
|
||||
gtk_column_view_column_set_reorderable (column, FALSE);
|
||||
gtk_column_view_append_column (GTK_COLUMN_VIEW (list), column);
|
||||
g_object_unref (column);
|
||||
|
||||
model = G_LIST_MODEL (gtk_single_selection_new (gtk_column_view_get_columns (GTK_COLUMN_VIEW (view))));
|
||||
gtk_column_view_set_model (GTK_COLUMN_VIEW (list), model);
|
||||
g_object_unref (model);
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), list);
|
||||
gtk_paned_set_end_child (GTK_PANED (paned), sw);
|
||||
|
||||
g_object_unref (scope);
|
||||
|
||||
controller = gtk_event_controller_key_new ();
|
||||
g_signal_connect (controller, "key-pressed", G_CALLBACK (key_pressed_cb), list);
|
||||
gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
|
||||
gtk_widget_add_controller (list, controller);
|
||||
|
||||
gtk_widget_show (win);
|
||||
|
||||
toplevels = gtk_window_get_toplevels ();
|
||||
|
||||
@@ -39,6 +39,7 @@ tests = [
|
||||
['listbox'],
|
||||
['main'],
|
||||
['maplistmodel'],
|
||||
['multiselection'],
|
||||
['notify'],
|
||||
['no-gtk-init'],
|
||||
['object'],
|
||||
|
||||
393
testsuite/gtk/multiselection.c
Normal file
393
testsuite/gtk/multiselection.c
Normal file
@@ -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 ();
|
||||
}
|
||||
@@ -425,7 +425,7 @@ test_autoselect (void)
|
||||
assert_model (selection, "1");
|
||||
assert_changes (selection, "+0");
|
||||
assert_selection (selection, "1");
|
||||
assert_selection_changes (selection, "0:1");
|
||||
assert_selection_changes (selection, "");
|
||||
|
||||
splice (store, 0, 1, (guint[]) { 7, 8, 9 }, 3);
|
||||
assert_model (selection, "7 8 9");
|
||||
|
||||
Reference in New Issue
Block a user