Commit 021d1632 authored by Georges Basile Stavracas Neto's avatar Georges Basile Stavracas Neto
Browse files

map-layer: Rework tile allocation

ShumateMapLayer currently breaks the GTK4 allocation model by calling
gtk_widget_size_allocate() outsize allocation, and by queueing allocation
during allocation (by removing and adding widgets).

Rework its allocation to not do that anymore. Make the allocation vfunc
only allocate, and never queue allocations.

Despite the scary diff, this change merely moves the contents of the
shumate_map_layer_compute_grid() function to inside the allocation
vfunc, and the contents of the allocation vfunc to recompute_grid().
parent ee1dac0d
......@@ -91,93 +91,128 @@ shumate_map_layer_get_tile_child (ShumateMapLayer *self,
}
static void
shumate_map_layer_compute_grid (ShumateMapLayer *self)
recompute_grid (ShumateMapLayer *self,
int width,
int height)
{
GtkWidget *widget = GTK_WIDGET (self);
guint required_tiles_x, required_tiles_y;
guint tile_size;
guint zoom_level;
double center_latitude, center_longitude;
guint center_x, center_y;
int x_offset, y_offset;
guint tile_x, tile_y;
guint tile_initial_x, tile_initial_y;
guint source_rows, source_columns;
int width, height;
GtkAllocation child_allocation;
ShumateViewport *viewport;
g_assert (SHUMATE_IS_MAP_LAYER (self));
viewport = shumate_layer_get_viewport (SHUMATE_LAYER (self));
tile_size = shumate_map_source_get_tile_size (self->map_source);
zoom_level = shumate_viewport_get_zoom_level (viewport);
center_latitude = shumate_location_get_latitude (SHUMATE_LOCATION (viewport));
center_longitude = shumate_location_get_longitude (SHUMATE_LOCATION (viewport));
center_x = (guint) shumate_map_source_get_x (self->map_source, zoom_level, center_longitude);
center_y = (guint) shumate_map_source_get_y (self->map_source, zoom_level, center_latitude);
source_rows = shumate_map_source_get_row_count (self->map_source, zoom_level);
source_columns = shumate_map_source_get_column_count (self->map_source, zoom_level);
width = gtk_widget_get_width (GTK_WIDGET (self));
height = gtk_widget_get_height (GTK_WIDGET (self));
required_tiles_x = (width / tile_size) + 2;
required_tiles_y = (height / tile_size) + 2;
if (self->required_tiles_x != required_tiles_x)
{
if (required_tiles_x > self->required_tiles_x)
{
for (guint x = self->required_tiles_x; x < required_tiles_x; x++)
{
for (guint y = 0; y < self->required_tiles_y; y++)
{
ShumateTile *tile;
TileGridPosition *tile_child;
// This is the (x,y) of the top left ShumateTile
tile_initial_x = (center_x - width/2)/tile_size;
tile_initial_y = (center_y - height/2)/tile_size;
tile = shumate_tile_new ();
shumate_tile_set_size (tile, tile_size);
gtk_widget_insert_before (GTK_WIDGET (tile), widget, NULL);
tile_child = tile_grid_position_new (tile, x, y);
g_ptr_array_add (self->tiles_positions, tile_child);
}
}
}
else
{
for (guint x = self->required_tiles_x - 1; x >= required_tiles_x; x--)
{
for (guint y = 0; y < self->required_tiles_y; y++)
{
TileGridPosition *tile_child = shumate_map_layer_get_tile_child (self, x, y);
if (!tile_child)
{
g_critical ("Unable to find tile to remove at (%u;%u)", x, y);
continue;
}
x_offset = (center_x - tile_initial_x * tile_size) - width/2;
y_offset = (center_y - tile_initial_y * tile_size) - height/2;
child_allocation.x = -x_offset;
child_allocation.width = tile_size;
child_allocation.height = tile_size;
gtk_widget_unparent (GTK_WIDGET (tile_child->tile));
g_ptr_array_remove_fast (self->tiles_positions, tile_child);
}
}
}
tile_x = tile_initial_x;
for (int x = 0; x < self->required_tiles_x; x++)
self->required_tiles_x = required_tiles_x;
}
if (self->required_tiles_y != required_tiles_y)
{
child_allocation.y = -y_offset;
tile_y = tile_initial_y;
for (int y = 0; y < self->required_tiles_y; y++)
if (required_tiles_y > self->required_tiles_y)
{
TileGridPosition *tile_child;
ShumateTile *child;
tile_child = shumate_map_layer_get_tile_child (self, x, y);
if (!tile_child)
for (guint x = 0; x < self->required_tiles_x; x++)
{
g_critical ("Unable to find tile at (%u;%u)", x, y);
for (guint y = self->required_tiles_y; y < required_tiles_y; y++)
{
ShumateTile *tile;
TileGridPosition *tile_child;
tile = shumate_tile_new ();
shumate_tile_set_size (tile, tile_size);
gtk_widget_insert_before (GTK_WIDGET (tile), widget, NULL);
tile_child = tile_grid_position_new (tile, x, y);
g_ptr_array_add (self->tiles_positions, tile_child);
}
}
else
}
else
{
for (guint x = 0; x < self->required_tiles_x; x++)
{
child = tile_child->tile;
gtk_widget_measure (GTK_WIDGET (child), GTK_ORIENTATION_HORIZONTAL, 0, NULL, NULL, NULL, NULL);
gtk_widget_size_allocate (GTK_WIDGET (child), &child_allocation, -1);
if (shumate_tile_get_zoom_level (child) != zoom_level ||
shumate_tile_get_x (child) != (tile_x % source_columns) ||
shumate_tile_get_y (child) != (tile_y % source_rows) ||
shumate_tile_get_state (child) == SHUMATE_STATE_NONE)
for (guint y = self->required_tiles_y - 1; y >= required_tiles_y; y--)
{
GCancellable *cancellable = g_hash_table_lookup (self->tile_fill, child);
if (cancellable)
g_cancellable_cancel (cancellable);
shumate_tile_set_zoom_level (child, zoom_level);
shumate_tile_set_x (child, tile_x % source_columns);
shumate_tile_set_y (child, tile_y % source_rows);
TileGridPosition *tile_child = shumate_map_layer_get_tile_child (self, x, y);
if (!tile_child)
{
g_critical ("Unable to find tile to remove at (%u;%u)", x, y);
continue;
}
cancellable = g_cancellable_new ();
shumate_tile_set_texture (child, NULL);
shumate_map_source_fill_tile (self->map_source, child, cancellable);
g_hash_table_insert (self->tile_fill, g_object_ref (child), cancellable);
gtk_widget_unparent (GTK_WIDGET (tile_child->tile));
g_ptr_array_remove_fast (self->tiles_positions, tile_child);
}
}
child_allocation.y += tile_size;
tile_y++;
}
child_allocation.x += tile_size;
tile_x++;
self->required_tiles_y = required_tiles_y;
}
}
static gboolean
grid_needs_recompute (ShumateMapLayer *self,
int width,
int height)
{
guint required_tiles_x, required_tiles_y;
guint tile_size;
tile_size = shumate_map_source_get_tile_size (self->map_source);
required_tiles_x = (width / tile_size) + 2;
required_tiles_y = (height / tile_size) + 2;
return self->required_tiles_x != required_tiles_x ||
self->required_tiles_y != required_tiles_y;
}
static void
maybe_recompute_grid (ShumateMapLayer *self)
{
int width, height;
width = gtk_widget_get_width (GTK_WIDGET (self));
height = gtk_widget_get_height (GTK_WIDGET (self));
if (grid_needs_recompute (self, width, height))
recompute_grid (self, width, height);
}
static void
on_view_longitude_changed (ShumateMapLayer *self,
GParamSpec *pspec,
......@@ -185,8 +220,8 @@ on_view_longitude_changed (ShumateMapLayer *self,
{
g_assert (SHUMATE_IS_MAP_LAYER (self));
shumate_map_layer_compute_grid (self);
gtk_widget_queue_draw (GTK_WIDGET (self));
maybe_recompute_grid (self);
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
......@@ -196,8 +231,8 @@ on_view_latitude_changed (ShumateMapLayer *self,
{
g_assert (SHUMATE_IS_MAP_LAYER (self));
shumate_map_layer_compute_grid (self);
gtk_widget_queue_draw (GTK_WIDGET (self));
maybe_recompute_grid (self);
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
......@@ -207,8 +242,8 @@ on_view_zoom_level_changed (ShumateMapLayer *self,
{
g_assert (SHUMATE_IS_MAP_LAYER (self));
shumate_map_layer_compute_grid (self);
gtk_widget_queue_draw (GTK_WIDGET (self));
maybe_recompute_grid (self);
gtk_widget_queue_allocate (GTK_WIDGET (self));
}
static void
......@@ -291,95 +326,86 @@ shumate_map_layer_size_allocate (GtkWidget *widget,
int baseline)
{
ShumateMapLayer *self = SHUMATE_MAP_LAYER (widget);
ShumateViewport *viewport;
GtkAllocation child_allocation;
guint tile_size;
guint required_tiles_x, required_tiles_y;
guint zoom_level;
double center_latitude, center_longitude;
guint center_x, center_y;
int x_offset, y_offset;
guint tile_x, tile_y;
guint tile_initial_x, tile_initial_y;
guint source_rows, source_columns;
viewport = shumate_layer_get_viewport (SHUMATE_LAYER (self));
tile_size = shumate_map_source_get_tile_size (self->map_source);
required_tiles_x = (width / tile_size) + 2;
required_tiles_y = (height / tile_size) + 2;
if (self->required_tiles_x != required_tiles_x)
{
if (required_tiles_x > self->required_tiles_x)
{
for (guint x = self->required_tiles_x; x < required_tiles_x; x++)
{
for (guint y = 0; y < self->required_tiles_y; y++)
{
ShumateTile *tile;
TileGridPosition *tile_child;
tile = shumate_tile_new ();
shumate_tile_set_size (tile, tile_size);
gtk_widget_insert_before (GTK_WIDGET (tile), widget, NULL);
tile_child = tile_grid_position_new (tile, x, y);
g_ptr_array_add (self->tiles_positions, tile_child);
}
}
}
else
{
for (guint x = self->required_tiles_x - 1; x >= required_tiles_x; x--)
{
for (guint y = 0; y < self->required_tiles_y; y++)
{
TileGridPosition *tile_child = shumate_map_layer_get_tile_child (self, x, y);
if (!tile_child)
{
g_critical ("Unable to find tile to remove at (%u;%u)", x, y);
continue;
}
zoom_level = shumate_viewport_get_zoom_level (viewport);
center_latitude = shumate_location_get_latitude (SHUMATE_LOCATION (viewport));
center_longitude = shumate_location_get_longitude (SHUMATE_LOCATION (viewport));
center_x = (guint) shumate_map_source_get_x (self->map_source, zoom_level, center_longitude);
center_y = (guint) shumate_map_source_get_y (self->map_source, zoom_level, center_latitude);
source_rows = shumate_map_source_get_row_count (self->map_source, zoom_level);
source_columns = shumate_map_source_get_column_count (self->map_source, zoom_level);
gtk_widget_unparent (GTK_WIDGET (tile_child->tile));
g_ptr_array_remove_fast (self->tiles_positions, tile_child);
}
}
}
// This is the (x,y) of the top left ShumateTile
tile_initial_x = (center_x - width/2)/tile_size;
tile_initial_y = (center_y - height/2)/tile_size;
self->required_tiles_x = required_tiles_x;
}
x_offset = (center_x - tile_initial_x * tile_size) - width/2;
y_offset = (center_y - tile_initial_y * tile_size) - height/2;
child_allocation.x = -x_offset;
child_allocation.width = tile_size;
child_allocation.height = tile_size;
if (self->required_tiles_y != required_tiles_y)
tile_x = tile_initial_x;
for (int x = 0; x < self->required_tiles_x; x++)
{
if (required_tiles_y > self->required_tiles_y)
child_allocation.y = -y_offset;
tile_y = tile_initial_y;
for (int y = 0; y < self->required_tiles_y; y++)
{
for (guint x = 0; x < self->required_tiles_x; x++)
{
for (guint y = self->required_tiles_y; y < required_tiles_y; y++)
{
ShumateTile *tile;
TileGridPosition *tile_child;
TileGridPosition *tile_child;
ShumateTile *child;
tile = shumate_tile_new ();
shumate_tile_set_size (tile, tile_size);
gtk_widget_insert_before (GTK_WIDGET (tile), widget, NULL);
tile_child = tile_grid_position_new (tile, x, y);
g_ptr_array_add (self->tiles_positions, tile_child);
}
tile_child = shumate_map_layer_get_tile_child (self, x, y);
if (!tile_child)
{
g_critical ("Unable to find tile at (%u;%u)", x, y);
}
}
else
{
for (guint x = 0; x < self->required_tiles_x; x++)
else
{
for (guint y = self->required_tiles_y - 1; y >= required_tiles_y; y--)
child = tile_child->tile;
gtk_widget_measure (GTK_WIDGET (child), GTK_ORIENTATION_HORIZONTAL, 0, NULL, NULL, NULL, NULL);
gtk_widget_size_allocate (GTK_WIDGET (child), &child_allocation, baseline);
if (shumate_tile_get_zoom_level (child) != zoom_level ||
shumate_tile_get_x (child) != (tile_x % source_columns) ||
shumate_tile_get_y (child) != (tile_y % source_rows) ||
shumate_tile_get_state (child) == SHUMATE_STATE_NONE)
{
TileGridPosition *tile_child = shumate_map_layer_get_tile_child (self, x, y);
if (!tile_child)
{
g_critical ("Unable to find tile to remove at (%u;%u)", x, y);
continue;
}
GCancellable *cancellable = g_hash_table_lookup (self->tile_fill, child);
if (cancellable)
g_cancellable_cancel (cancellable);
gtk_widget_unparent (GTK_WIDGET (tile_child->tile));
g_ptr_array_remove_fast (self->tiles_positions, tile_child);
shumate_tile_set_zoom_level (child, zoom_level);
shumate_tile_set_x (child, tile_x % source_columns);
shumate_tile_set_y (child, tile_y % source_rows);
cancellable = g_cancellable_new ();
shumate_tile_set_texture (child, NULL);
shumate_map_source_fill_tile (self->map_source, child, cancellable);
g_hash_table_insert (self->tile_fill, g_object_ref (child), cancellable);
}
}
child_allocation.y += tile_size;
tile_y++;
}
self->required_tiles_y = required_tiles_y;
child_allocation.x += tile_size;
tile_x++;
}
shumate_map_layer_compute_grid (self);
}
static void
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment