Compare commits
25 Commits
gdk-win32-
...
wip/matthi
Author | SHA1 | Date | |
---|---|---|---|
|
0b156637a5 | ||
|
73696a8521 | ||
|
b772b4600d | ||
|
7aa7d7be16 | ||
|
8793ab183d | ||
|
b1353457d4 | ||
|
49b03b8a84 | ||
|
5cc40f1e5a | ||
|
b1723c1b0c | ||
|
bfa2e6725e | ||
|
5620ffcbfd | ||
|
d94fc2d4e2 | ||
|
702ee8cb1e | ||
|
0fe56ad497 | ||
|
4e18d469bc | ||
|
b694aef7a6 | ||
|
631ee08d9a | ||
|
bbe9e9bcdd | ||
|
ff46f050f5 | ||
|
9a66ec81bf | ||
|
e5f0e17378 | ||
|
c7d295dd9b | ||
|
2e30806d42 | ||
|
56907ad66f | ||
|
9cb94c1547 |
@@ -19,16 +19,18 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include "gtkgridview.h"
|
#include "gtkgridviewprivate.h"
|
||||||
|
|
||||||
#include "gtkbitset.h"
|
#include "gtkbitset.h"
|
||||||
#include "gtklistbaseprivate.h"
|
#include "gtklistbaseprivate.h"
|
||||||
|
#include "gtklistheaderwidgetprivate.h"
|
||||||
#include "gtklistitemfactory.h"
|
#include "gtklistitemfactory.h"
|
||||||
#include "gtklistitemmanagerprivate.h"
|
#include "gtklistitemmanagerprivate.h"
|
||||||
#include "gtklistitemwidgetprivate.h"
|
#include "gtklistitemwidgetprivate.h"
|
||||||
#include "gtkmultiselection.h"
|
#include "gtkmultiselection.h"
|
||||||
#include "gtktypebuiltins.h"
|
#include "gtktypebuiltins.h"
|
||||||
#include "gtkwidgetprivate.h"
|
#include "gtkwidgetprivate.h"
|
||||||
|
#include "gtksectionmodel.h"
|
||||||
|
|
||||||
/* Maximum number of list items created by the gridview.
|
/* Maximum number of list items created by the gridview.
|
||||||
* For debugging, you can set this to G_MAXUINT to ensure
|
* For debugging, you can set this to G_MAXUINT to ensure
|
||||||
@@ -87,12 +89,19 @@ struct _GtkGridView
|
|||||||
|
|
||||||
GtkListItemManager *item_manager;
|
GtkListItemManager *item_manager;
|
||||||
GtkListItemFactory *factory;
|
GtkListItemFactory *factory;
|
||||||
|
GtkListItemFactory *header_factory;
|
||||||
guint min_columns;
|
guint min_columns;
|
||||||
guint max_columns;
|
guint max_columns;
|
||||||
gboolean single_click_activate;
|
gboolean single_click_activate;
|
||||||
/* set in size_allocate */
|
/* set in size_allocate */
|
||||||
guint n_columns;
|
guint n_columns;
|
||||||
double column_width;
|
double column_width;
|
||||||
|
|
||||||
|
/* for debugging between get_position_from_allocation and size_allocate */
|
||||||
|
unsigned int anchor_position;
|
||||||
|
unsigned int anchor_column;
|
||||||
|
unsigned int anchor_n_columns;
|
||||||
|
gboolean anchor_has_sections;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GtkGridViewClass
|
struct _GtkGridViewClass
|
||||||
@@ -105,6 +114,7 @@ enum
|
|||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_ENABLE_RUBBERBAND,
|
PROP_ENABLE_RUBBERBAND,
|
||||||
PROP_FACTORY,
|
PROP_FACTORY,
|
||||||
|
PROP_HEADER_FACTORY,
|
||||||
PROP_MAX_COLUMNS,
|
PROP_MAX_COLUMNS,
|
||||||
PROP_MIN_COLUMNS,
|
PROP_MIN_COLUMNS,
|
||||||
PROP_MODEL,
|
PROP_MODEL,
|
||||||
@@ -257,6 +267,13 @@ gtk_grid_view_split (GtkListBase *base,
|
|||||||
return split;
|
return split;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_grid_view_prepare_section (GtkListBase *base,
|
||||||
|
GtkListTile *tile,
|
||||||
|
guint position)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/* We define the listview as **inert** when the factory isn't used. */
|
/* We define the listview as **inert** when the factory isn't used. */
|
||||||
static gboolean
|
static gboolean
|
||||||
gtk_grid_view_is_inert (GtkGridView *self)
|
gtk_grid_view_is_inert (GtkGridView *self)
|
||||||
@@ -269,7 +286,8 @@ gtk_grid_view_is_inert (GtkGridView *self)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_grid_view_update_factories_with (GtkGridView *self,
|
gtk_grid_view_update_factories_with (GtkGridView *self,
|
||||||
GtkListItemFactory *factory)
|
GtkListItemFactory *factory,
|
||||||
|
GtkListItemFactory *header_factory)
|
||||||
{
|
{
|
||||||
GtkListTile *tile;
|
GtkListTile *tile;
|
||||||
|
|
||||||
@@ -277,8 +295,26 @@ gtk_grid_view_update_factories_with (GtkGridView *self,
|
|||||||
tile != NULL;
|
tile != NULL;
|
||||||
tile = gtk_rb_tree_node_get_next (tile))
|
tile = gtk_rb_tree_node_get_next (tile))
|
||||||
{
|
{
|
||||||
if (tile->widget)
|
switch (tile->type)
|
||||||
gtk_list_factory_widget_set_factory (GTK_LIST_FACTORY_WIDGET (tile->widget), factory);
|
{
|
||||||
|
case GTK_LIST_TILE_ITEM:
|
||||||
|
if (tile->widget)
|
||||||
|
gtk_list_factory_widget_set_factory (GTK_LIST_FACTORY_WIDGET (tile->widget), factory);
|
||||||
|
break;
|
||||||
|
case GTK_LIST_TILE_HEADER:
|
||||||
|
if (tile->widget)
|
||||||
|
gtk_list_header_widget_set_factory (GTK_LIST_HEADER_WIDGET (tile->widget), header_factory);
|
||||||
|
break;
|
||||||
|
case GTK_LIST_TILE_UNMATCHED_HEADER:
|
||||||
|
case GTK_LIST_TILE_FOOTER:
|
||||||
|
case GTK_LIST_TILE_UNMATCHED_FOOTER:
|
||||||
|
case GTK_LIST_TILE_REMOVED:
|
||||||
|
g_assert (tile->widget == NULL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,13 +322,14 @@ static void
|
|||||||
gtk_grid_view_update_factories (GtkGridView *self)
|
gtk_grid_view_update_factories (GtkGridView *self)
|
||||||
{
|
{
|
||||||
gtk_grid_view_update_factories_with (self,
|
gtk_grid_view_update_factories_with (self,
|
||||||
gtk_grid_view_is_inert (self) ? NULL : self->factory);
|
gtk_grid_view_is_inert (self) ? NULL : self->factory,
|
||||||
|
gtk_grid_view_is_inert (self) ? NULL : self->header_factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_grid_view_clear_factories (GtkGridView *self)
|
gtk_grid_view_clear_factories (GtkGridView *self)
|
||||||
{
|
{
|
||||||
gtk_grid_view_update_factories_with (self, NULL);
|
gtk_grid_view_update_factories_with (self, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GtkListItemBase *
|
static GtkListItemBase *
|
||||||
@@ -316,6 +353,20 @@ gtk_grid_view_create_list_widget (GtkListBase *base)
|
|||||||
return GTK_LIST_ITEM_BASE (result);
|
return GTK_LIST_ITEM_BASE (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GtkListHeaderBase *
|
||||||
|
gtk_grid_view_create_header_widget (GtkListBase *base)
|
||||||
|
{
|
||||||
|
GtkGridView *self = GTK_GRID_VIEW (base);
|
||||||
|
GtkListItemFactory *factory;
|
||||||
|
|
||||||
|
if (gtk_grid_view_is_inert (self))
|
||||||
|
factory = NULL;
|
||||||
|
else
|
||||||
|
factory = self->header_factory;
|
||||||
|
|
||||||
|
return GTK_LIST_HEADER_BASE (gtk_list_header_widget_new (factory));
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gtk_grid_view_get_allocation (GtkListBase *base,
|
gtk_grid_view_get_allocation (GtkListBase *base,
|
||||||
guint pos,
|
guint pos,
|
||||||
@@ -384,6 +435,79 @@ gtk_grid_view_get_allocation (GtkListBase *base,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns the section that position falls into
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
get_section_for_position (GtkListItemManager *items,
|
||||||
|
unsigned int position,
|
||||||
|
unsigned int *section_start,
|
||||||
|
unsigned int *section_end)
|
||||||
|
{
|
||||||
|
GListModel *model;
|
||||||
|
unsigned int start, end;
|
||||||
|
|
||||||
|
model = G_LIST_MODEL (gtk_list_item_manager_get_model (items));
|
||||||
|
|
||||||
|
if (!gtk_list_item_manager_get_has_sections (items))
|
||||||
|
{
|
||||||
|
start = 0;
|
||||||
|
end = g_list_model_get_n_items (model);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gtk_section_model_get_section (GTK_SECTION_MODEL (model), position, &start, &end);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (section_start)
|
||||||
|
*section_start = start;
|
||||||
|
if (section_end)
|
||||||
|
*section_end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the column that the given item will fall in, taking
|
||||||
|
* sections into account. Note that this depends on whether
|
||||||
|
* we are currently showing sections, and on the number of
|
||||||
|
* columns that the grid is allocating.
|
||||||
|
*/
|
||||||
|
unsigned int
|
||||||
|
gtk_grid_view_get_column_for_position (GtkListItemManager *items,
|
||||||
|
unsigned int n_columns,
|
||||||
|
unsigned int position)
|
||||||
|
{
|
||||||
|
unsigned int start;
|
||||||
|
|
||||||
|
get_section_for_position (items, position, &start, NULL);
|
||||||
|
|
||||||
|
return (position - start) % n_columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine whether a tile is contained in a single row,
|
||||||
|
* or spans multiple rows.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
gtk_grid_view_is_multirow_tile (GtkListItemManager *items,
|
||||||
|
unsigned int n_columns,
|
||||||
|
GtkListTile *tile)
|
||||||
|
{
|
||||||
|
unsigned int position;
|
||||||
|
unsigned int start, start2;
|
||||||
|
unsigned int col;
|
||||||
|
|
||||||
|
if (tile->n_items <= 1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
position = gtk_list_tile_get_position (items, tile);
|
||||||
|
get_section_for_position (items, position, &start, NULL);
|
||||||
|
get_section_for_position (items, position + tile->n_items - 1, &start2, NULL);
|
||||||
|
|
||||||
|
if (start != start2)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
col = (position - start) % n_columns;
|
||||||
|
|
||||||
|
return col + tile->n_items - 1 > n_columns;
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gtk_grid_view_get_position_from_allocation (GtkListBase *base,
|
gtk_grid_view_get_position_from_allocation (GtkListBase *base,
|
||||||
int x,
|
int x,
|
||||||
@@ -394,6 +518,7 @@ gtk_grid_view_get_position_from_allocation (GtkListBase *base,
|
|||||||
GtkGridView *self = GTK_GRID_VIEW (base);
|
GtkGridView *self = GTK_GRID_VIEW (base);
|
||||||
GtkListTile *tile;
|
GtkListTile *tile;
|
||||||
guint pos;
|
guint pos;
|
||||||
|
guint col;
|
||||||
|
|
||||||
tile = gtk_list_item_manager_get_nearest_tile (self->item_manager, x, y);
|
tile = gtk_list_item_manager_get_nearest_tile (self->item_manager, x, y);
|
||||||
if (tile == NULL)
|
if (tile == NULL)
|
||||||
@@ -411,44 +536,43 @@ gtk_grid_view_get_position_from_allocation (GtkListBase *base,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pos = gtk_list_tile_get_position (self->item_manager, tile);
|
pos = gtk_list_tile_get_position (self->item_manager, tile);
|
||||||
|
col = gtk_grid_view_get_column_for_position (self->item_manager, self->n_columns, pos);
|
||||||
|
|
||||||
if (tile->n_items > 1)
|
if (tile->n_items > 1)
|
||||||
{
|
{
|
||||||
int xspacing, yspacing;
|
int xspacing, yspacing;
|
||||||
|
guint row_height;
|
||||||
|
guint row_index;
|
||||||
|
|
||||||
gtk_list_base_get_border_spacing (base, &xspacing, &yspacing);
|
gtk_list_base_get_border_spacing (base, &xspacing, &yspacing);
|
||||||
|
|
||||||
/* offset in x direction */
|
/* offset in x direction */
|
||||||
pos += column_index (self, xspacing, MAX (tile->area.width - 1, x - tile->area.x));
|
pos += column_index (self, xspacing, MAX (tile->area.width - 1, x - tile->area.x)) - col;
|
||||||
if (area)
|
|
||||||
{
|
|
||||||
guint col = MIN (column_index (self, xspacing, x), self->n_columns - 1);
|
|
||||||
area->x = column_start (self, xspacing, col);
|
|
||||||
area->width = column_end (self, xspacing, col) - area->x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* offset in y direction */
|
/* offset in y direction */
|
||||||
if (tile->n_items > self->n_columns)
|
if (tile->n_items > self->n_columns)
|
||||||
{
|
{
|
||||||
guint rows_in_tile = tile->n_items / self->n_columns;
|
guint rows_in_tile = tile->n_items / self->n_columns;
|
||||||
guint row_height = (tile->area.height + yspacing) / rows_in_tile - yspacing;
|
|
||||||
guint row_index = MIN (tile->area.height - 1, y - tile->area.y) / (row_height + yspacing);
|
|
||||||
pos += self->n_columns * row_index;
|
|
||||||
|
|
||||||
if (area)
|
row_height = (tile->area.height + yspacing) / rows_in_tile - yspacing;
|
||||||
{
|
row_index = MIN (tile->area.height - 1, y - tile->area.y) / (row_height + yspacing);
|
||||||
area->y = tile->area.y + row_index * (row_height + yspacing);
|
pos += self->n_columns * row_index;
|
||||||
area->height = row_height;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (area)
|
row_height = tile->area.height;
|
||||||
{
|
row_index = 0;
|
||||||
area->y = tile->area.y;
|
|
||||||
area->height = tile->area.height;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
col = gtk_grid_view_get_column_for_position (self->item_manager, self->n_columns, pos);
|
||||||
|
|
||||||
|
if (area)
|
||||||
|
{
|
||||||
|
area->x = column_start (self, xspacing, col);
|
||||||
|
area->width = column_end (self, xspacing, col) - area->x;
|
||||||
|
area->y = tile->area.y + row_index * (row_height + yspacing);
|
||||||
|
area->height = row_height;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -456,6 +580,11 @@ gtk_grid_view_get_position_from_allocation (GtkListBase *base,
|
|||||||
*area = tile->area;
|
*area = tile->area;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self->anchor_position = pos;
|
||||||
|
self->anchor_column = col;
|
||||||
|
self->anchor_n_columns = self->n_columns;
|
||||||
|
self->anchor_has_sections = gtk_list_item_manager_get_has_sections (self->item_manager);
|
||||||
|
|
||||||
*position = pos;
|
*position = pos;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -632,6 +761,86 @@ gtk_grid_view_compute_n_columns (GtkGridView *self,
|
|||||||
return n_columns;
|
return n_columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gtk_grid_view_split_tiles_by_columns (GtkListItemManager *items,
|
||||||
|
guint n_columns)
|
||||||
|
{
|
||||||
|
GtkListTile *tile;
|
||||||
|
|
||||||
|
tile = gtk_list_item_manager_get_first (items);
|
||||||
|
|
||||||
|
while (tile != NULL)
|
||||||
|
{
|
||||||
|
/* Handle multirow tiles first */
|
||||||
|
if (tile->n_items > 1)
|
||||||
|
{
|
||||||
|
guint pos, col;
|
||||||
|
guint end, remaining;
|
||||||
|
|
||||||
|
pos = gtk_list_tile_get_position (items, tile);
|
||||||
|
col = gtk_grid_view_get_column_for_position (items, n_columns, pos);
|
||||||
|
get_section_for_position (items, pos, NULL, &end);
|
||||||
|
|
||||||
|
if (col > 0)
|
||||||
|
{
|
||||||
|
/* Determine if the first row needs to be split off */
|
||||||
|
remaining = MIN (n_columns - col, end - 1 - pos);
|
||||||
|
if (remaining > 0 && tile->n_items > remaining)
|
||||||
|
{
|
||||||
|
gtk_list_tile_split (items, tile, remaining);
|
||||||
|
tile = gtk_rb_tree_node_get_next (tile);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += tile->n_items - 1;
|
||||||
|
col = gtk_grid_view_get_column_for_position (items, n_columns, pos);
|
||||||
|
get_section_for_position (items, pos, NULL, &end);
|
||||||
|
|
||||||
|
if (col < n_columns - 1)
|
||||||
|
{
|
||||||
|
/* Determine if the last row needs to be split off */
|
||||||
|
remaining = MIN (n_columns - (col - 1), end - 1 - pos);
|
||||||
|
if (remaining > 0 && col + 1 < tile->n_items)
|
||||||
|
{
|
||||||
|
gtk_list_tile_split (items, tile, tile->n_items - (col + 1));
|
||||||
|
tile = gtk_rb_tree_node_get_next (tile);
|
||||||
|
tile = gtk_rb_tree_node_get_next (tile);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tile = gtk_rb_tree_node_get_next (tile);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef G_ENABLE_DEBUG
|
||||||
|
/* Verify some invariants:
|
||||||
|
* - there are no removed tiles left
|
||||||
|
* - multirow tiles start in column 0
|
||||||
|
* - non-multirow tiles are contained in one row
|
||||||
|
*/
|
||||||
|
for (tile = gtk_list_item_manager_get_first (items);
|
||||||
|
tile != NULL;
|
||||||
|
tile = gtk_rb_tree_node_get_next (tile))
|
||||||
|
{
|
||||||
|
g_assert (tile->type != GTK_LIST_TILE_REMOVED);
|
||||||
|
if (tile->n_items > 1)
|
||||||
|
{
|
||||||
|
unsigned int pos, col;
|
||||||
|
|
||||||
|
pos = gtk_list_tile_get_position (items, tile);
|
||||||
|
col = gtk_grid_view_get_column_for_position (items, n_columns, pos);
|
||||||
|
|
||||||
|
if (gtk_grid_view_is_multirow_tile (items, n_columns, tile))
|
||||||
|
g_assert (col == 0);
|
||||||
|
else
|
||||||
|
g_assert (col + tile->n_items - 1 <= n_columns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_grid_view_measure_list (GtkWidget *widget,
|
gtk_grid_view_measure_list (GtkWidget *widget,
|
||||||
int for_size,
|
int for_size,
|
||||||
@@ -670,7 +879,7 @@ gtk_grid_view_measure_list (GtkWidget *widget,
|
|||||||
{
|
{
|
||||||
gtk_widget_measure (tile->widget,
|
gtk_widget_measure (tile->widget,
|
||||||
gtk_list_base_get_orientation (GTK_LIST_BASE (self)),
|
gtk_list_base_get_orientation (GTK_LIST_BASE (self)),
|
||||||
column_size,
|
gtk_list_tile_is_header (tile) ? for_size : column_size,
|
||||||
&child_min, &child_nat, NULL, NULL);
|
&child_min, &child_nat, NULL, NULL);
|
||||||
if (scroll_policy == GTK_SCROLL_MINIMUM)
|
if (scroll_policy == GTK_SCROLL_MINIMUM)
|
||||||
row_height = MAX (row_height, child_min);
|
row_height = MAX (row_height, child_min);
|
||||||
@@ -679,7 +888,10 @@ gtk_grid_view_measure_list (GtkWidget *widget,
|
|||||||
measured = TRUE;
|
measured = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
i += tile->n_items;
|
if (gtk_list_tile_is_footer (tile) || gtk_list_tile_is_header (tile))
|
||||||
|
i = n_columns;
|
||||||
|
else
|
||||||
|
i += tile->n_items;
|
||||||
|
|
||||||
if (i >= n_columns)
|
if (i >= n_columns)
|
||||||
{
|
{
|
||||||
@@ -775,34 +987,34 @@ gtk_grid_view_size_allocate (GtkWidget *widget,
|
|||||||
self->column_width = ((orientation == GTK_ORIENTATION_VERTICAL ? width : height) + xspacing) / self->n_columns - xspacing;
|
self->column_width = ((orientation == GTK_ORIENTATION_VERTICAL ? width : height) + xspacing) / self->n_columns - xspacing;
|
||||||
self->column_width = MAX (self->column_width, col_min);
|
self->column_width = MAX (self->column_width, col_min);
|
||||||
|
|
||||||
/* step 2: determine height of known rows */
|
/* step 2: split tiles as required */
|
||||||
|
gtk_grid_view_split_tiles_by_columns (self->item_manager, self->n_columns);
|
||||||
|
|
||||||
|
/* step 3: determine height of known rows */
|
||||||
heights = g_array_new (FALSE, FALSE, sizeof (int));
|
heights = g_array_new (FALSE, FALSE, sizeof (int));
|
||||||
|
|
||||||
|
tile = gtk_list_item_manager_get_first (self->item_manager);
|
||||||
while (tile != NULL)
|
while (tile != NULL)
|
||||||
{
|
{
|
||||||
/* if it's a multirow tile, handle it here */
|
if (gtk_grid_view_is_multirow_tile (self->item_manager, self->n_columns, tile))
|
||||||
if (tile->n_items > 1 && tile->n_items >= self->n_columns)
|
|
||||||
{
|
{
|
||||||
if (tile->n_items % self->n_columns)
|
|
||||||
gtk_list_tile_split (self->item_manager, tile, tile->n_items / self->n_columns * self->n_columns);
|
|
||||||
tile = gtk_rb_tree_node_get_next (tile);
|
tile = gtk_rb_tree_node_get_next (tile);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Not a multirow tile */
|
|
||||||
i = 0;
|
|
||||||
row_height = 0;
|
row_height = 0;
|
||||||
|
|
||||||
for (i = 0, start = tile;
|
for (i = 0, start = tile;
|
||||||
i < self->n_columns && tile != NULL;
|
i < self->n_columns && tile != NULL;
|
||||||
tile = gtk_rb_tree_node_get_next (tile))
|
tile = gtk_rb_tree_node_get_next (tile))
|
||||||
{
|
{
|
||||||
|
g_assert (!gtk_grid_view_is_multirow_tile (self->item_manager, self->n_columns, tile));
|
||||||
if (tile->widget)
|
if (tile->widget)
|
||||||
{
|
{
|
||||||
int min, nat, size;
|
int min, nat, size;
|
||||||
gtk_widget_measure (tile->widget,
|
gtk_widget_measure (tile->widget,
|
||||||
gtk_list_base_get_orientation (GTK_LIST_BASE (self)),
|
gtk_list_base_get_orientation (GTK_LIST_BASE (self)),
|
||||||
self->column_width,
|
gtk_list_tile_is_header (tile) ? width : self->column_width,
|
||||||
&min, &nat, NULL, NULL);
|
&min, &nat, NULL, NULL);
|
||||||
if (scroll_policy == GTK_SCROLL_MINIMUM)
|
if (scroll_policy == GTK_SCROLL_MINIMUM)
|
||||||
size = min;
|
size = min;
|
||||||
@@ -812,32 +1024,59 @@ gtk_grid_view_size_allocate (GtkWidget *widget,
|
|||||||
g_array_append_val (heights, size);
|
g_array_append_val (heights, size);
|
||||||
row_height = MAX (row_height, size);
|
row_height = MAX (row_height, size);
|
||||||
}
|
}
|
||||||
if (tile->n_items > self->n_columns - i)
|
if (gtk_list_tile_is_footer (tile) || gtk_list_tile_is_header (tile))
|
||||||
gtk_list_tile_split (self->item_manager, tile, self->n_columns - i);
|
i = self->n_columns;
|
||||||
i += tile->n_items;
|
else
|
||||||
|
i += tile->n_items;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row_height > 0)
|
if (row_height > 0)
|
||||||
{
|
{
|
||||||
for (i = 0;
|
for (i = 0;
|
||||||
start != tile;
|
start != tile;
|
||||||
start = gtk_rb_tree_node_get_next (start))
|
start = gtk_rb_tree_node_get_next (start))
|
||||||
{
|
{
|
||||||
|
int n_columns;
|
||||||
|
int tile_height;
|
||||||
|
|
||||||
|
if (gtk_list_tile_is_footer (start))
|
||||||
|
{
|
||||||
|
n_columns = self->n_columns - i;
|
||||||
|
if (n_columns != 0 && n_columns != self->n_columns)
|
||||||
|
tile_height = row_height;
|
||||||
|
else
|
||||||
|
tile_height = 0;
|
||||||
|
}
|
||||||
|
else if (gtk_list_tile_is_header (start))
|
||||||
|
{
|
||||||
|
g_assert (i == 0);
|
||||||
|
n_columns = self->n_columns;
|
||||||
|
if (gtk_list_item_manager_get_has_sections (self->item_manager))
|
||||||
|
tile_height = row_height;
|
||||||
|
else
|
||||||
|
tile_height = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n_columns = start->n_items;
|
||||||
|
tile_height = row_height;
|
||||||
|
}
|
||||||
|
|
||||||
gtk_list_tile_set_area_size (self->item_manager,
|
gtk_list_tile_set_area_size (self->item_manager,
|
||||||
start,
|
start,
|
||||||
column_end (self, xspacing, i + start->n_items - 1)
|
column_end (self, xspacing, i + n_columns - 1)
|
||||||
- column_start (self, xspacing, i),
|
- column_start (self, xspacing, i),
|
||||||
row_height);
|
tile_height);
|
||||||
i += start->n_items;
|
i += n_columns;
|
||||||
}
|
}
|
||||||
g_assert (i <= self->n_columns);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* step 3: determine height of rows with only unknown items */
|
/* step 4: determine height of rows with only unknown items */
|
||||||
unknown_row_height = gtk_grid_view_get_unknown_row_size (self, heights);
|
unknown_row_height = gtk_grid_view_get_unknown_row_size (self, heights);
|
||||||
g_array_free (heights, TRUE);
|
g_array_free (heights, TRUE);
|
||||||
|
|
||||||
/* step 4: determine height for remaining rows and set each row's position */
|
/* step 5: determine height for remaining rows and set each row's position */
|
||||||
y = 0;
|
y = 0;
|
||||||
i = 0;
|
i = 0;
|
||||||
for (tile = gtk_list_item_manager_get_first (self->item_manager);
|
for (tile = gtk_list_item_manager_get_first (self->item_manager);
|
||||||
@@ -848,55 +1087,71 @@ gtk_grid_view_size_allocate (GtkWidget *widget,
|
|||||||
tile,
|
tile,
|
||||||
column_start (self, xspacing, i),
|
column_start (self, xspacing, i),
|
||||||
y);
|
y);
|
||||||
if (tile->n_items >= self->n_columns && tile->widget == NULL)
|
|
||||||
|
if (gtk_list_tile_is_footer (tile))
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
i = self->n_columns;
|
||||||
|
|
||||||
|
if (!gtk_list_item_manager_get_has_sections (self->item_manager) && i == 0)
|
||||||
|
gtk_list_tile_set_area_size (self->item_manager,
|
||||||
|
tile,
|
||||||
|
column_end (self, xspacing, self->n_columns - 1)
|
||||||
|
- column_start (self, xspacing, 0),
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
else if (gtk_list_tile_is_header (tile))
|
||||||
{
|
{
|
||||||
g_assert (i == 0);
|
g_assert (i == 0);
|
||||||
g_assert (tile->n_items % self->n_columns == 0);
|
i = self->n_columns;
|
||||||
gtk_list_tile_set_area_size (self->item_manager,
|
|
||||||
tile,
|
if (!gtk_list_item_manager_get_has_sections (self->item_manager))
|
||||||
column_end (self, xspacing, self->n_columns - 1)
|
gtk_list_tile_set_area_size (self->item_manager,
|
||||||
- column_start (self, xspacing, 0),
|
tile,
|
||||||
(unknown_row_height + yspacing) * (tile->n_items / self->n_columns) - yspacing);
|
column_end (self, xspacing, self->n_columns - 1)
|
||||||
y += tile->area.height + yspacing;
|
- column_start (self, xspacing, 0),
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (tile->area.height == 0)
|
if (gtk_list_tile_get_position (self->item_manager, tile) == self->anchor_position &&
|
||||||
|
i != self->anchor_column)
|
||||||
|
{
|
||||||
|
g_print ("BAD: anchor column mismatch (anchor %u, column %u != %u, n_columns %u vs %u, sections %d vs %d)\n",
|
||||||
|
self->anchor_position,
|
||||||
|
self->anchor_column, i,
|
||||||
|
self->anchor_n_columns, self->n_columns,
|
||||||
|
self->anchor_has_sections, gtk_list_item_manager_get_has_sections (self->item_manager));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gtk_grid_view_is_multirow_tile (self->item_manager, self->n_columns, tile))
|
||||||
|
{
|
||||||
|
g_assert (i == 0);
|
||||||
|
gtk_list_tile_set_area_size (self->item_manager,
|
||||||
|
tile,
|
||||||
|
column_end (self, xspacing, self->n_columns - 1)
|
||||||
|
- column_start (self, xspacing, 0),
|
||||||
|
(unknown_row_height + yspacing) * (tile->n_items / self->n_columns) - yspacing);
|
||||||
|
y += tile->area.height + yspacing;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
/* this case is for the last row - it may not be a full row so it won't
|
|
||||||
* be a multirow tile but it may have no widgets either */
|
|
||||||
gtk_list_tile_set_area_size (self->item_manager,
|
gtk_list_tile_set_area_size (self->item_manager,
|
||||||
tile,
|
tile,
|
||||||
column_end (self, xspacing, i + tile->n_items - 1) - tile->area.x,
|
column_end (self, xspacing, i + tile->n_items - 1) - tile->area.x,
|
||||||
unknown_row_height);
|
unknown_row_height);
|
||||||
|
i += tile->n_items;
|
||||||
}
|
}
|
||||||
i += tile->n_items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i >= self->n_columns)
|
if (i >= self->n_columns)
|
||||||
{
|
{
|
||||||
g_assert (i == self->n_columns);
|
|
||||||
y += tile->area.height + yspacing;
|
y += tile->area.height + yspacing;
|
||||||
i = 0;
|
i = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Add a filler tile for empty space in the bottom right */
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
GtkListTile *footer = gtk_list_item_manager_get_last (self->item_manager);
|
|
||||||
g_assert (gtk_list_tile_is_footer (footer));
|
|
||||||
tile = gtk_rb_tree_node_get_previous (footer);
|
|
||||||
gtk_list_tile_set_area_position (self->item_manager,
|
|
||||||
footer,
|
|
||||||
column_start (self, xspacing, i),
|
|
||||||
y);
|
|
||||||
gtk_list_tile_set_area_size (self->item_manager,
|
|
||||||
footer,
|
|
||||||
column_end (self, xspacing, self->n_columns - 1) - footer->area.x,
|
|
||||||
tile->area.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* step 4: allocate the rest */
|
/* step 6: allocate the widgets */
|
||||||
gtk_list_base_allocate (GTK_LIST_BASE (self));
|
gtk_list_base_allocate (GTK_LIST_BASE (self));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -952,6 +1207,7 @@ gtk_grid_view_dispose (GObject *object)
|
|||||||
self->item_manager = NULL;
|
self->item_manager = NULL;
|
||||||
|
|
||||||
g_clear_object (&self->factory);
|
g_clear_object (&self->factory);
|
||||||
|
g_clear_object (&self->header_factory);
|
||||||
|
|
||||||
G_OBJECT_CLASS (gtk_grid_view_parent_class)->dispose (object);
|
G_OBJECT_CLASS (gtk_grid_view_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
@@ -974,6 +1230,10 @@ gtk_grid_view_get_property (GObject *object,
|
|||||||
g_value_set_object (value, self->factory);
|
g_value_set_object (value, self->factory);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_HEADER_FACTORY:
|
||||||
|
g_value_set_object (value, self->header_factory);
|
||||||
|
break;
|
||||||
|
|
||||||
case PROP_MAX_COLUMNS:
|
case PROP_MAX_COLUMNS:
|
||||||
g_value_set_uint (value, self->max_columns);
|
g_value_set_uint (value, self->max_columns);
|
||||||
break;
|
break;
|
||||||
@@ -1018,6 +1278,10 @@ gtk_grid_view_set_property (GObject *object,
|
|||||||
gtk_grid_view_set_factory (self, g_value_get_object (value));
|
gtk_grid_view_set_factory (self, g_value_get_object (value));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_HEADER_FACTORY:
|
||||||
|
gtk_grid_view_set_header_factory (self, g_value_get_object (value));
|
||||||
|
break;
|
||||||
|
|
||||||
case PROP_MAX_COLUMNS:
|
case PROP_MAX_COLUMNS:
|
||||||
gtk_grid_view_set_max_columns (self, g_value_get_uint (value));
|
gtk_grid_view_set_max_columns (self, g_value_get_uint (value));
|
||||||
break;
|
break;
|
||||||
@@ -1071,6 +1335,8 @@ gtk_grid_view_class_init (GtkGridViewClass *klass)
|
|||||||
|
|
||||||
list_base_class->split = gtk_grid_view_split;
|
list_base_class->split = gtk_grid_view_split;
|
||||||
list_base_class->create_list_widget = gtk_grid_view_create_list_widget;
|
list_base_class->create_list_widget = gtk_grid_view_create_list_widget;
|
||||||
|
list_base_class->prepare_section = gtk_grid_view_prepare_section;
|
||||||
|
list_base_class->create_header_widget = gtk_grid_view_create_header_widget;
|
||||||
list_base_class->get_allocation = gtk_grid_view_get_allocation;
|
list_base_class->get_allocation = gtk_grid_view_get_allocation;
|
||||||
list_base_class->get_items_in_rect = gtk_grid_view_get_items_in_rect;
|
list_base_class->get_items_in_rect = gtk_grid_view_get_items_in_rect;
|
||||||
list_base_class->get_position_from_allocation = gtk_grid_view_get_position_from_allocation;
|
list_base_class->get_position_from_allocation = gtk_grid_view_get_position_from_allocation;
|
||||||
@@ -1109,6 +1375,19 @@ gtk_grid_view_class_init (GtkGridViewClass *klass)
|
|||||||
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GtkGridView:header-factory: (attributes org.gtk.Property.get=gtk_grid_view_get_header_factory org.gtk.Property.set=gtk_grid_view_set_header_factory)
|
||||||
|
*
|
||||||
|
* Factory for creating header widgets.
|
||||||
|
*
|
||||||
|
* Since: 4.12
|
||||||
|
*/
|
||||||
|
properties[PROP_HEADER_FACTORY] =
|
||||||
|
g_param_spec_object ("header-factory", NULL, NULL,
|
||||||
|
GTK_TYPE_LIST_ITEM_FACTORY,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GtkGridView:max-columns: (attributes org.gtk.Property.get=gtk_grid_view_get_max_columns org.gtk.Property.set=gtk_grid_view_set_max_columns)
|
* GtkGridView:max-columns: (attributes org.gtk.Property.get=gtk_grid_view_get_max_columns org.gtk.Property.set=gtk_grid_view_set_max_columns)
|
||||||
*
|
*
|
||||||
@@ -1342,6 +1621,69 @@ gtk_grid_view_set_factory (GtkGridView *self,
|
|||||||
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FACTORY]);
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FACTORY]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_grid_view_get_header_factory: (attributes org.gtk.Method.get_property=header-factory)
|
||||||
|
* @self: a `GtkGridView`
|
||||||
|
*
|
||||||
|
* Gets the factory that's currently used to populate section headers.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer none): The factory in use
|
||||||
|
*
|
||||||
|
* Since: 4.12
|
||||||
|
*/
|
||||||
|
GtkListItemFactory *
|
||||||
|
gtk_grid_view_get_header_factory (GtkGridView *self)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (GTK_IS_GRID_VIEW (self), NULL);
|
||||||
|
|
||||||
|
return self->header_factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gtk_grid_view_set_header_factory: (attributes org.gtk.Method.set_property=header-factory)
|
||||||
|
* @self: a `GtkGridView`
|
||||||
|
* @factory: (nullable) (transfer none): the factory to use
|
||||||
|
*
|
||||||
|
* Sets the `GtkListItemFactory` to use for populating the
|
||||||
|
* [class@Gtk.ListHeader] objects used in section headers.
|
||||||
|
*
|
||||||
|
* If this factory is set to %NULL, the list will not show section headers.
|
||||||
|
*
|
||||||
|
* Since: 4.12
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gtk_grid_view_set_header_factory (GtkGridView *self,
|
||||||
|
GtkListItemFactory *factory)
|
||||||
|
{
|
||||||
|
gboolean had_sections;
|
||||||
|
|
||||||
|
g_return_if_fail (GTK_IS_GRID_VIEW (self));
|
||||||
|
g_return_if_fail (factory == NULL || GTK_IS_LIST_ITEM_FACTORY (factory));
|
||||||
|
|
||||||
|
had_sections = gtk_list_item_manager_get_has_sections (self->item_manager);
|
||||||
|
|
||||||
|
if (!g_set_object (&self->header_factory, factory))
|
||||||
|
return;
|
||||||
|
|
||||||
|
gtk_list_item_manager_set_has_sections (self->item_manager, factory != NULL);
|
||||||
|
|
||||||
|
if (!gtk_grid_view_is_inert (self) &&
|
||||||
|
had_sections && gtk_list_item_manager_get_has_sections (self->item_manager))
|
||||||
|
{
|
||||||
|
GtkListTile *tile;
|
||||||
|
|
||||||
|
for (tile = gtk_list_item_manager_get_first (self->item_manager);
|
||||||
|
tile != NULL;
|
||||||
|
tile = gtk_rb_tree_node_get_next (tile))
|
||||||
|
{
|
||||||
|
if (tile->widget && tile->type == GTK_LIST_TILE_HEADER)
|
||||||
|
gtk_list_header_widget_set_factory (GTK_LIST_HEADER_WIDGET (tile->widget), factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEADER_FACTORY]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gtk_grid_view_get_max_columns: (attributes org.gtk.Method.get_property=max-columns)
|
* gtk_grid_view_get_max_columns: (attributes org.gtk.Method.get_property=max-columns)
|
||||||
* @self: a `GtkGridView`
|
* @self: a `GtkGridView`
|
||||||
|
@@ -56,6 +56,14 @@ void gtk_grid_view_set_factory (GtkGridView
|
|||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
GtkListItemFactory *
|
GtkListItemFactory *
|
||||||
gtk_grid_view_get_factory (GtkGridView *self);
|
gtk_grid_view_get_factory (GtkGridView *self);
|
||||||
|
|
||||||
|
GDK_AVAILABLE_IN_4_12
|
||||||
|
void gtk_grid_view_set_header_factory (GtkGridView *self,
|
||||||
|
GtkListItemFactory *factory);
|
||||||
|
GDK_AVAILABLE_IN_4_12
|
||||||
|
GtkListItemFactory *
|
||||||
|
gtk_grid_view_get_header_factory (GtkGridView *self);
|
||||||
|
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
guint gtk_grid_view_get_min_columns (GtkGridView *self);
|
guint gtk_grid_view_get_min_columns (GtkGridView *self);
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
|
40
gtk/gtkgridviewprivate.h
Normal file
40
gtk/gtkgridviewprivate.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2023 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "gtk/gtktypes.h"
|
||||||
|
#include "gtk/gtkenums.h"
|
||||||
|
#include "gtk/gtkgridview.h"
|
||||||
|
#include "gtk/gtklistitemmanagerprivate.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
unsigned int gtk_grid_view_get_column_for_position (GtkListItemManager *items,
|
||||||
|
unsigned int n_columns,
|
||||||
|
unsigned int position);
|
||||||
|
|
||||||
|
gboolean gtk_grid_view_is_multirow_tile (GtkListItemManager *items,
|
||||||
|
unsigned int n_columns,
|
||||||
|
GtkListTile *tile);
|
||||||
|
|
||||||
|
|
||||||
|
void gtk_grid_view_split_tiles_by_columns (GtkListItemManager *items,
|
||||||
|
guint n_columns);
|
||||||
|
|
||||||
|
G_END_DECLS
|
@@ -39,6 +39,8 @@
|
|||||||
#include "gtktypebuiltins.h"
|
#include "gtktypebuiltins.h"
|
||||||
#include "gtkwidgetprivate.h"
|
#include "gtkwidgetprivate.h"
|
||||||
|
|
||||||
|
#include <gdk/gdkrgbaprivate.h>
|
||||||
|
|
||||||
/* Allow shadows to overdraw without immediately culling the widget at the viewport
|
/* Allow shadows to overdraw without immediately culling the widget at the viewport
|
||||||
* boundary.
|
* boundary.
|
||||||
* Choose this so that roughly 1 extra widget gets drawn on each side of the viewport,
|
* Choose this so that roughly 1 extra widget gets drawn on each side of the viewport,
|
||||||
@@ -1142,6 +1144,124 @@ gtk_list_base_move_cursor (GtkWidget *widget,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GskRenderNode *
|
||||||
|
gtk_list_base_dump_tiles (GtkListBase *self)
|
||||||
|
{
|
||||||
|
GtkListBasePrivate *priv = gtk_list_base_get_instance_private (self);
|
||||||
|
GtkSnapshot *snapshot;
|
||||||
|
GtkListTile *tile;
|
||||||
|
cairo_rectangle_int_t viewport;
|
||||||
|
guint i, focus, anchor, selected;
|
||||||
|
PangoLayout *layout;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
focus = gtk_list_base_get_focus_position (self);
|
||||||
|
anchor = gtk_list_base_get_anchor (self);
|
||||||
|
selected = gtk_list_item_tracker_get_position (priv->item_manager, priv->selected);
|
||||||
|
|
||||||
|
snapshot = gtk_snapshot_new ();
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for (tile = gtk_list_item_manager_get_first (priv->item_manager);
|
||||||
|
tile != NULL;
|
||||||
|
tile = gtk_rb_tree_node_get_next (tile))
|
||||||
|
{
|
||||||
|
if (tile->widget)
|
||||||
|
{
|
||||||
|
GdkRGBA color;
|
||||||
|
if (gtk_list_tile_is_header (tile))
|
||||||
|
color = GDK_RGBA("FF00FF");
|
||||||
|
else if (i == focus)
|
||||||
|
color = GDK_RGBA("00FF00");
|
||||||
|
else if (i == anchor)
|
||||||
|
color = GDK_RGBA("FFFF00");
|
||||||
|
else if (i == selected)
|
||||||
|
color = GDK_RGBA("0000FF");
|
||||||
|
else
|
||||||
|
color = GDK_RGBA("FFFFFF");
|
||||||
|
|
||||||
|
gtk_snapshot_append_color (snapshot,
|
||||||
|
&color,
|
||||||
|
&GRAPHENE_RECT_INIT(
|
||||||
|
tile->area.x, tile->area.y,
|
||||||
|
tile->area.width, tile->area.height
|
||||||
|
));
|
||||||
|
|
||||||
|
/* This should really look at the ListItem */
|
||||||
|
s = g_strdup_printf ("%u", i);
|
||||||
|
layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), s);
|
||||||
|
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (tile->area.x + 2, tile->area.y + 2));
|
||||||
|
gtk_snapshot_append_layout (snapshot, layout, &GDK_RGBA("000000"));
|
||||||
|
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (- tile->area.x - 2, - tile->area.y - 2));
|
||||||
|
g_object_unref (layout);
|
||||||
|
g_free (s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GdkRGBA color;
|
||||||
|
|
||||||
|
if (gtk_list_tile_is_footer (tile))
|
||||||
|
color = GDK_RGBA("800080");
|
||||||
|
if (tile->n_items == 0)
|
||||||
|
color = GDK_RGBA("A07070");
|
||||||
|
else
|
||||||
|
color = GDK_RGBA("808080");
|
||||||
|
gtk_snapshot_append_color (snapshot,
|
||||||
|
&color,
|
||||||
|
&GRAPHENE_RECT_INIT(
|
||||||
|
tile->area.x, tile->area.y,
|
||||||
|
tile->area.width, tile->area.height
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_snapshot_append_border (snapshot,
|
||||||
|
&GSK_ROUNDED_RECT_INIT(
|
||||||
|
tile->area.x, tile->area.y,
|
||||||
|
tile->area.width, tile->area.height
|
||||||
|
),
|
||||||
|
(float[4]) { 1, 1, 1, 1 },
|
||||||
|
(GdkRGBA[4]) { GDK_RGBA("000000"), GDK_RGBA("000000"), GDK_RGBA("000000"), GDK_RGBA("000000") });
|
||||||
|
|
||||||
|
i += tile->n_items;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_list_base_get_adjustment_values (GTK_LIST_BASE (self),
|
||||||
|
gtk_list_base_get_orientation (GTK_LIST_BASE (self)),
|
||||||
|
&viewport.y, NULL, &viewport.height);
|
||||||
|
gtk_list_base_get_adjustment_values (GTK_LIST_BASE (self),
|
||||||
|
gtk_list_base_get_opposite_orientation (GTK_LIST_BASE (self)),
|
||||||
|
&viewport.x, NULL, &viewport.width);
|
||||||
|
gtk_snapshot_append_color (snapshot,
|
||||||
|
&GDK_RGBA("0000F040"),
|
||||||
|
&GRAPHENE_RECT_INIT(
|
||||||
|
viewport.x, viewport.y,
|
||||||
|
viewport.width, viewport.height
|
||||||
|
));
|
||||||
|
|
||||||
|
|
||||||
|
return gtk_snapshot_free_to_node (snapshot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gtk_list_base_copy_tiles_to_clipboard (GtkWidget *widget,
|
||||||
|
GVariant *args,
|
||||||
|
gpointer unused)
|
||||||
|
{
|
||||||
|
GtkListBase *self = GTK_LIST_BASE (widget);
|
||||||
|
GskRenderNode *node;
|
||||||
|
|
||||||
|
node = gtk_list_base_dump_tiles (self);
|
||||||
|
if (node == NULL)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
gdk_clipboard_set (gtk_widget_get_clipboard (widget),
|
||||||
|
GSK_TYPE_RENDER_NODE,
|
||||||
|
node);
|
||||||
|
gsk_render_node_unref (node);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_list_base_add_move_binding (GtkWidgetClass *widget_class,
|
gtk_list_base_add_move_binding (GtkWidgetClass *widget_class,
|
||||||
guint keyval,
|
guint keyval,
|
||||||
@@ -1320,6 +1440,8 @@ 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_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_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_backslash, GDK_CONTROL_MASK, "list.unselect-all", NULL);
|
||||||
|
|
||||||
|
gtk_widget_class_add_binding (widget_class, GDK_KEY_R, GDK_CONTROL_MASK | GDK_SHIFT_MASK, gtk_list_base_copy_tiles_to_clipboard, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@@ -95,3 +95,5 @@ GtkListTabBehavior gtk_list_base_get_tab_behavior (GtkListBase
|
|||||||
|
|
||||||
void gtk_list_base_allocate (GtkListBase *self);
|
void gtk_list_base_allocate (GtkListBase *self);
|
||||||
|
|
||||||
|
GskRenderNode *gtk_list_base_dump_tiles (GtkListBase *self);
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
gtk_tests = [
|
gtk_tests = [
|
||||||
# testname, optional extra sources
|
# testname, optional extra sources
|
||||||
|
['testsections'],
|
||||||
['testfilelauncher'],
|
['testfilelauncher'],
|
||||||
['input'],
|
['input'],
|
||||||
['testpopup'],
|
['testpopup'],
|
||||||
|
317
tests/testsections.c
Normal file
317
tests/testsections.c
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup_item (GtkSignalListItemFactory *self,
|
||||||
|
GObject *object)
|
||||||
|
{
|
||||||
|
GtkListItem *list_item = GTK_LIST_ITEM (object);
|
||||||
|
GtkWidget *child = gtk_label_new ("");
|
||||||
|
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (child), 0);
|
||||||
|
gtk_list_item_set_child (list_item, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bind_item (GtkSignalListItemFactory *self,
|
||||||
|
GObject *object)
|
||||||
|
{
|
||||||
|
GtkListItem *list_item = GTK_LIST_ITEM (object);
|
||||||
|
GObject *item = gtk_list_item_get_item (list_item);
|
||||||
|
GtkWidget *child = gtk_list_item_get_child (list_item);
|
||||||
|
|
||||||
|
gtk_label_set_label (GTK_LABEL (child),
|
||||||
|
gtk_string_object_get_string (GTK_STRING_OBJECT (item)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup_header (GtkSignalListItemFactory *self,
|
||||||
|
GObject *object)
|
||||||
|
{
|
||||||
|
GtkListHeader *header = GTK_LIST_HEADER (object);
|
||||||
|
GtkWidget *child = gtk_label_new ("");
|
||||||
|
|
||||||
|
gtk_label_set_xalign (GTK_LABEL (child), 0);
|
||||||
|
gtk_list_header_set_child (header, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
get_first (GObject *this)
|
||||||
|
{
|
||||||
|
const char *s = gtk_string_object_get_string (GTK_STRING_OBJECT (this));
|
||||||
|
char buffer[6] = { 0, };
|
||||||
|
|
||||||
|
g_unichar_to_utf8 (g_unichar_toupper (g_utf8_get_char (s)), buffer);
|
||||||
|
|
||||||
|
return g_strdup (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bind_header (GtkSignalListItemFactory *self,
|
||||||
|
GObject *object)
|
||||||
|
{
|
||||||
|
GtkListHeader *header = GTK_LIST_HEADER (object);
|
||||||
|
GObject *item = gtk_list_header_get_item (header);
|
||||||
|
GtkWidget *child = gtk_list_header_get_child (header);
|
||||||
|
PangoAttrList *attrs;
|
||||||
|
char *string;
|
||||||
|
|
||||||
|
string = get_first (item);
|
||||||
|
|
||||||
|
gtk_label_set_label (GTK_LABEL (child), string);
|
||||||
|
attrs = pango_attr_list_new ();
|
||||||
|
pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_X_LARGE));
|
||||||
|
pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
|
||||||
|
gtk_label_set_attributes (GTK_LABEL (child), attrs);
|
||||||
|
pango_attr_list_unref (attrs);
|
||||||
|
g_free (string);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *strings[] = {
|
||||||
|
"Alpha", "Andromeda", "Anaphylaxis", "Anaheim", "Beer", "Branch", "Botulism", "Banana",
|
||||||
|
"Bee", "Crane", "Caldera", "Copper", "Crowd", "Dora", "Dolphin", "Dam", "Ding",
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
gboolean done_reading = FALSE;
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
dump_sections (gpointer data)
|
||||||
|
{
|
||||||
|
GtkSectionModel *model = data;
|
||||||
|
|
||||||
|
if (!done_reading)
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (model)); i++)
|
||||||
|
{
|
||||||
|
unsigned int s, e;
|
||||||
|
gtk_section_model_get_section (model, i, &s, &e);
|
||||||
|
g_print ("(%u %u)\n", s, e - 1);
|
||||||
|
i = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
read_lines_cb (GObject *object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GBufferedInputStream *stream = G_BUFFERED_INPUT_STREAM (object);
|
||||||
|
GtkStringList *stringlist = data;
|
||||||
|
GError *error = NULL;
|
||||||
|
gsize size;
|
||||||
|
GPtrArray *lines;
|
||||||
|
gssize n_filled;
|
||||||
|
const char *buffer, *newline;
|
||||||
|
|
||||||
|
n_filled = g_buffered_input_stream_fill_finish (stream, result, &error);
|
||||||
|
if (n_filled < 0)
|
||||||
|
{
|
||||||
|
g_print ("Could not read data: %s\n", error->message);
|
||||||
|
g_clear_error (&error);
|
||||||
|
g_object_unref (stringlist);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = g_buffered_input_stream_peek_buffer (stream, &size);
|
||||||
|
|
||||||
|
if (n_filled == 0)
|
||||||
|
{
|
||||||
|
if (size)
|
||||||
|
gtk_string_list_take (stringlist, g_utf8_make_valid (buffer, size));
|
||||||
|
g_object_unref (stringlist);
|
||||||
|
done_reading = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = NULL;
|
||||||
|
while ((newline = memchr (buffer, '\n', size)))
|
||||||
|
{
|
||||||
|
if (newline > buffer)
|
||||||
|
{
|
||||||
|
if (lines == NULL)
|
||||||
|
lines = g_ptr_array_new_with_free_func (g_free);
|
||||||
|
g_ptr_array_add (lines, g_utf8_make_valid (buffer, newline - buffer));
|
||||||
|
}
|
||||||
|
if (g_input_stream_skip (G_INPUT_STREAM (stream), newline - buffer + 1, NULL, &error) < 0)
|
||||||
|
{
|
||||||
|
g_clear_error (&error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buffer = g_buffered_input_stream_peek_buffer (stream, &size);
|
||||||
|
}
|
||||||
|
if (lines == NULL)
|
||||||
|
{
|
||||||
|
g_buffered_input_stream_set_buffer_size (stream, g_buffered_input_stream_get_buffer_size (stream) + 4096);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_ptr_array_add (lines, NULL);
|
||||||
|
gtk_string_list_splice (stringlist, g_list_model_get_n_items (G_LIST_MODEL (stringlist)), 0, (const char **) lines->pdata);
|
||||||
|
g_ptr_array_free (lines, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_buffered_input_stream_fill_async (stream, -1, G_PRIORITY_HIGH_IDLE, NULL, read_lines_cb, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
file_is_open_cb (GObject *file,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
GFileInputStream *file_stream;
|
||||||
|
GBufferedInputStream *stream;
|
||||||
|
|
||||||
|
file_stream = g_file_read_finish (G_FILE (file), result, &error);
|
||||||
|
if (file_stream == NULL)
|
||||||
|
{
|
||||||
|
g_print ("Could not open file: %s\n", error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
g_object_unref (data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = G_BUFFERED_INPUT_STREAM (g_buffered_input_stream_new (G_INPUT_STREAM (file_stream)));
|
||||||
|
g_buffered_input_stream_fill_async (stream, -1, G_PRIORITY_HIGH_IDLE, NULL, read_lines_cb, data);
|
||||||
|
g_object_unref (stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_file (GtkStringList *list,
|
||||||
|
GFile *file)
|
||||||
|
{
|
||||||
|
gtk_string_list_splice (list, 0, g_list_model_get_n_items (G_LIST_MODEL (list)), NULL);
|
||||||
|
g_file_read_async (file, G_PRIORITY_HIGH_IDLE, NULL, file_is_open_cb, g_object_ref (list));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
toggle_cb (GtkCheckButton *check, GtkWidget *list)
|
||||||
|
{
|
||||||
|
GtkListItemFactory *header_factory = NULL;
|
||||||
|
|
||||||
|
if (gtk_check_button_get_active (check))
|
||||||
|
{
|
||||||
|
header_factory = gtk_signal_list_item_factory_new ();
|
||||||
|
g_signal_connect (header_factory, "setup", G_CALLBACK (setup_header), NULL);
|
||||||
|
g_signal_connect (header_factory, "bind", G_CALLBACK (bind_header), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GTK_IS_LIST_VIEW (list))
|
||||||
|
gtk_list_view_set_header_factory (GTK_LIST_VIEW (list), header_factory);
|
||||||
|
else
|
||||||
|
gtk_grid_view_set_header_factory (GTK_GRID_VIEW (list), header_factory);
|
||||||
|
|
||||||
|
g_clear_object (&header_factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
value_changed_cb (GtkAdjustment *adj, gpointer data)
|
||||||
|
{
|
||||||
|
g_print ("horizontal adjustment changed to %f\n", gtk_adjustment_get_value (adj));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
GtkWidget *window;
|
||||||
|
GtkWidget *sw;
|
||||||
|
GtkWidget *lv;
|
||||||
|
GtkWidget *gv;
|
||||||
|
GtkWidget *header;
|
||||||
|
GtkWidget *toggle;
|
||||||
|
GtkWidget *switcher;
|
||||||
|
GtkWidget *stack;
|
||||||
|
GtkListItemFactory *factory;
|
||||||
|
GtkExpression *expression;
|
||||||
|
GtkSortListModel *sortmodel;
|
||||||
|
GtkSelectionModel *selection;
|
||||||
|
GtkStringList *stringlist;
|
||||||
|
GtkAdjustment *adj;
|
||||||
|
|
||||||
|
stringlist = gtk_string_list_new (NULL);
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
{
|
||||||
|
GFile *file = g_file_new_for_commandline_arg (argv[1]);
|
||||||
|
load_file (stringlist, file);
|
||||||
|
g_object_unref (file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; strings[i]; i++)
|
||||||
|
gtk_string_list_append (stringlist, strings[i]);
|
||||||
|
done_reading = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_init ();
|
||||||
|
|
||||||
|
window = gtk_window_new ();
|
||||||
|
gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
|
||||||
|
|
||||||
|
header = gtk_header_bar_new ();
|
||||||
|
gtk_window_set_titlebar (GTK_WINDOW (window), header);
|
||||||
|
|
||||||
|
toggle = gtk_check_button_new ();
|
||||||
|
gtk_widget_set_valign (toggle, GTK_ALIGN_CENTER);
|
||||||
|
gtk_header_bar_pack_start (GTK_HEADER_BAR (header), toggle);
|
||||||
|
|
||||||
|
stack = gtk_stack_new ();
|
||||||
|
gtk_window_set_child (GTK_WINDOW (window), stack);
|
||||||
|
|
||||||
|
switcher = gtk_stack_switcher_new ();
|
||||||
|
gtk_header_bar_set_title_widget (GTK_HEADER_BAR (header), switcher);
|
||||||
|
|
||||||
|
gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER (switcher), GTK_STACK (stack));
|
||||||
|
|
||||||
|
expression = gtk_property_expression_new (GTK_TYPE_STRING_OBJECT, NULL, "string");
|
||||||
|
sortmodel = gtk_sort_list_model_new (G_LIST_MODEL (stringlist),
|
||||||
|
GTK_SORTER (gtk_string_sorter_new (expression)));
|
||||||
|
expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL, 0, NULL, (GCallback) get_first, NULL, NULL);
|
||||||
|
gtk_sort_list_model_set_section_sorter (sortmodel, GTK_SORTER (gtk_string_sorter_new (expression)));
|
||||||
|
selection = GTK_SELECTION_MODEL (gtk_no_selection_new (G_LIST_MODEL (sortmodel)));
|
||||||
|
|
||||||
|
sw = gtk_scrolled_window_new ();
|
||||||
|
gtk_stack_add_titled (GTK_STACK (stack), sw, "list", "List");
|
||||||
|
|
||||||
|
factory = gtk_signal_list_item_factory_new ();
|
||||||
|
g_signal_connect (factory, "setup", G_CALLBACK (setup_item), NULL);
|
||||||
|
g_signal_connect (factory, "bind", G_CALLBACK (bind_item), NULL);
|
||||||
|
|
||||||
|
lv = gtk_list_view_new (g_object_ref (selection), factory);
|
||||||
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), lv);
|
||||||
|
|
||||||
|
g_signal_connect (toggle, "toggled", G_CALLBACK (toggle_cb), lv);
|
||||||
|
|
||||||
|
sw = gtk_scrolled_window_new ();
|
||||||
|
gtk_stack_add_titled (GTK_STACK (stack), sw, "grid", "Grid");
|
||||||
|
|
||||||
|
factory = gtk_signal_list_item_factory_new ();
|
||||||
|
g_signal_connect (factory, "setup", G_CALLBACK (setup_item), NULL);
|
||||||
|
g_signal_connect (factory, "bind", G_CALLBACK (bind_item), NULL);
|
||||||
|
|
||||||
|
gv = gtk_grid_view_new (g_object_ref (selection), factory);
|
||||||
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), gv);
|
||||||
|
|
||||||
|
g_signal_connect (toggle, "toggled", G_CALLBACK (toggle_cb), gv);
|
||||||
|
|
||||||
|
gtk_grid_view_set_min_columns (GTK_GRID_VIEW (gv), 5);
|
||||||
|
|
||||||
|
adj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (sw));
|
||||||
|
g_signal_connect (adj, "value-changed", G_CALLBACK (value_changed_cb), NULL);
|
||||||
|
|
||||||
|
gtk_window_present (GTK_WINDOW (window));
|
||||||
|
|
||||||
|
g_timeout_add (500, dump_sections, selection);
|
||||||
|
|
||||||
|
while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0)
|
||||||
|
g_main_context_iteration (NULL, FALSE);
|
||||||
|
|
||||||
|
g_object_unref (selection);
|
||||||
|
g_object_unref (stringlist);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@@ -20,6 +20,7 @@
|
|||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
#include "gtk/gtklistitemmanagerprivate.h"
|
#include "gtk/gtklistitemmanagerprivate.h"
|
||||||
#include "gtk/gtklistbaseprivate.h"
|
#include "gtk/gtklistbaseprivate.h"
|
||||||
|
#include "gtk/gtkgridviewprivate.h"
|
||||||
|
|
||||||
static GListModel *
|
static GListModel *
|
||||||
create_source_model (guint min_size, guint max_size)
|
create_source_model (guint min_size, guint max_size)
|
||||||
@@ -374,7 +375,43 @@ print_changes_cb (GListModel *model,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_exhaustive (void)
|
check_column_tile_invariants (GtkListItemManager *items,
|
||||||
|
unsigned int n_columns)
|
||||||
|
{
|
||||||
|
GtkListTile *tile;
|
||||||
|
|
||||||
|
for (tile = gtk_list_item_manager_get_first (items);
|
||||||
|
tile != NULL;
|
||||||
|
tile = gtk_rb_tree_node_get_next (tile))
|
||||||
|
{
|
||||||
|
g_assert (tile->type != GTK_LIST_TILE_REMOVED);
|
||||||
|
if (tile->n_items > 1)
|
||||||
|
{
|
||||||
|
unsigned int pos, col;
|
||||||
|
|
||||||
|
pos = gtk_list_tile_get_position (items, tile);
|
||||||
|
col = gtk_grid_view_get_column_for_position (items, n_columns, pos);
|
||||||
|
|
||||||
|
if (gtk_grid_view_is_multirow_tile (items, n_columns, tile))
|
||||||
|
g_assert_true (col == 0);
|
||||||
|
else
|
||||||
|
g_assert_true (col + tile->n_items - 1 <= n_columns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
check_grid_view (GtkListItemManager *items)
|
||||||
|
{
|
||||||
|
for (unsigned int n_columns = 1; n_columns < 10; n_columns++)
|
||||||
|
{
|
||||||
|
gtk_list_item_manager_gc_tiles (items);
|
||||||
|
gtk_grid_view_split_tiles_by_columns (items, n_columns);
|
||||||
|
check_column_tile_invariants (items, n_columns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_exhaustive (gboolean grid)
|
||||||
{
|
{
|
||||||
GtkListItemTracker *trackers[N_TRACKERS];
|
GtkListItemTracker *trackers[N_TRACKERS];
|
||||||
GListStore *store;
|
GListStore *store;
|
||||||
@@ -484,7 +521,10 @@ test_exhaustive (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
check_list_item_manager (items, trackers, N_TRACKERS);
|
if (grid)
|
||||||
|
check_grid_view (items);
|
||||||
|
else
|
||||||
|
check_list_item_manager (items, trackers, N_TRACKERS);
|
||||||
|
|
||||||
for (i = 0; i < N_TRACKERS; i++)
|
for (i = 0; i < N_TRACKERS; i++)
|
||||||
gtk_list_item_tracker_free (items, trackers[i]);
|
gtk_list_item_tracker_free (items, trackers[i]);
|
||||||
@@ -492,6 +532,18 @@ test_exhaustive (void)
|
|||||||
gtk_window_destroy (GTK_WINDOW (widget));
|
gtk_window_destroy (GTK_WINDOW (widget));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_exhaustive_list (void)
|
||||||
|
{
|
||||||
|
test_exhaustive (FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_exhaustive_grid (void)
|
||||||
|
{
|
||||||
|
test_exhaustive (TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char *argv[])
|
main (int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@@ -499,7 +551,8 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
g_test_add_func ("/listitemmanager/create", test_create);
|
g_test_add_func ("/listitemmanager/create", test_create);
|
||||||
g_test_add_func ("/listitemmanager/create_with_items", test_create_with_items);
|
g_test_add_func ("/listitemmanager/create_with_items", test_create_with_items);
|
||||||
g_test_add_func ("/listitemmanager/exhaustive", test_exhaustive);
|
g_test_add_func ("/listitemmanager/exhaustive", test_exhaustive_list);
|
||||||
|
g_test_add_func ("/gridview/split", test_exhaustive_grid);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user