[libshumate] map-layer: Rework tile allocation



commit 021d16327b6f9fe5b050027dac1f080fbf9448d5
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date:   Fri Mar 5 18:05:46 2021 -0300

    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().

 shumate/shumate-map-layer.c | 312 ++++++++++++++++++++++++--------------------
 1 file changed, 169 insertions(+), 143 deletions(-)
---
diff --git a/shumate/shumate-map-layer.c b/shumate/shumate-map-layer.c
index 682ebb2..8d96121 100644
--- a/shumate/shumate-map-layer.c
+++ b/shumate/shumate-map-layer.c
@@ -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


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]