Signal / Property to connect when a GtkWidget is allocated

Hi,

I need to know the widget (Shumate.SimpleMap) allocated size to determine a map bounding box. This calculation is done before the window containing the widget is shown on screen.

I try to connect to several signals (map, realize, show) but the widget’s methods get_allocated_height() or get_allocated_width() always return 0.

So, what signal / property should I connect to in order for these methods to return the allocated size ? Or do I have to wait for the window to be shown on screen to perform this calculation ?

Kind regards,
@vcottineau

There is no signal for that.

The only way to know when a widget is allocated is to write your own widget subclass; then you can override the GtkWidgetClass.size_allocate() virtual function and get the allocation size as given to you by the parent widget.

@ebassi,

Thanks for your reply.
Can you provide a sample code to achieve your suggestion ?

Regards,
@vcottineau

Not really, because it depends on what you want to achieve, and whether or not the widget you are using allows code to derive from it.

@ebassi,

Below are some code extracts.
I am using a Shumate.SimpleMap wich is a Gtk.Widget.

Main window containing the Shumate.SimpleMap in a Gtk.Box:

@Gtk.Template(resource_path="/com/github/pygpxviewer/ui/GpxDetailedView.ui")
class GpxDetailedView(Adw.Window):
    """Display an interactive map and a chart to analyse a gpx file."""

    __gtype_name__ = "GpxDetailedView"

    _menu_button = Gtk.Template.Child()
    _box_container = Gtk.Template.Child()
    _points_label = Gtk.Template.Child()
    _length_label = Gtk.Template.Child()
    _up_hill_label = Gtk.Template.Child()
    _down_hill_label = Gtk.Template.Child()

    def __init__(self, path):
        super().__init__()

Shumate.SimpleMap widget:

class ShumateMap(Shumate.SimpleMap):
    """Display an interactive map.

    Contains the following elements:
        * Zoom
        * License
        * Scale
        * Compass
    """

    def __init__(self, window):
        super().__init__()

        self._settings = Gio.Settings.new("com.github.pygpxviewer.app.window.detailed.map")
        self._gpx_helper = window.gpx_helper

        self._path_layer = None
        self._marker_layer = None
        self._marker = None

        self._set_map()
        self._set_marker()
        self._set_layers()

During the __init__(), I am calling this method (in which I need the widget allocated height and width for calculations):

    def set_center_and_zoom(self) -> None:
        """Set map center and zoom based on the path layer bounds.

        Link: https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames
        FixMe: Improve calculations if poles / 180th meridian is crossed

        @return: None
        @rtype: None
        """

        def get_latitude_derivation(latitude):
            radians = math.radians(latitude)
            return math.asinh(math.tan(radians)) / math.pi / 2

        def get_latitude_derivation_reverse(latitude_derivation):
            radians = math.atan(math.sinh(latitude_derivation * 2 * math.pi))
            return math.degrees(radians)

        bounds = self._gpx_helper.gpx.get_bounds()

        min_latitude = bounds.min_latitude
        min_longitude = bounds.min_longitude
        max_latitude = bounds.max_latitude
        max_longitude = bounds.max_longitude

        min_latitude_derivation = get_latitude_derivation(min_latitude)
        max_latitude_derivation = get_latitude_derivation(max_latitude)
        mean_latitude_derivation = (min_latitude_derivation + max_latitude_derivation) / 2

        latitude_fraction = max_latitude_derivation - min_latitude_derivation
        longitude_fraction = (max_longitude - min_longitude) / 360

        tile_size = self.get_map_source().get_tile_size()
        map_height = 363 * 0.95  # self.get_allocated_height() | Offset
        map_width = 599 * 0.95  # self.get_allocated_width() | Offset

        max_zoom_level = self.get_map_source().get_max_zoom_level()
        latitude_zoom_level = math.log(map_height / tile_size / latitude_fraction) / math.log(2)
        longitude_zoom_level = math.log(map_width / tile_size / longitude_fraction) / math.log(2)
        zoom_level = min(max_zoom_level, latitude_zoom_level, longitude_zoom_level)

        self.get_map().go_to_full(
            get_latitude_derivation_reverse(mean_latitude_derivation),
            (min_longitude + max_longitude) / 2,
            zoom_level)

Regards,
@vcottineau

You should override the size_allocate() virtual function of Gtk.Widget by adding:

def do_size_allocate(self, width: int, height: int, baseline: int) -> None:
    # Chain up
    Shumate.SimpleMap.do_size_allocate(self, width, height, baseline)
    # do something with width and height

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.