GtkPicture+GtkLabel in horizontal GtkBox: hexpand and halign ignored

I have a GtkPicture+GtkLabel in horizontal GtkBox. I want that the image (see post end for used image) never grows past its original dimensions (148x98) and that the label is flush to the image, without padding or spacing whatsoever. In other words:

  • Picture: Vertex 1 at (0,0) (coordinates relative to window, not to display) and vertex 2 is never, ever further than (148,98).
  • Label: Vertex 1 is at {picture’s vertex 2 + 1}, i.e., no spacing between picture and label.

So I use align=1 and expand=0 for the picture, whereas expand=1 for the label:

import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk

class MainWindow(Gtk.ApplicationWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)

        image = Gtk.Image.new_from_file("xeyes.png");
        image = Gtk.Picture.new_for_filename("xeyes.png");
        image.set_content_fit(3)
        image.set_halign(1)
        image.set_hexpand(False)
        image.set_vexpand(False)
        box.append(image)

        label = Gtk.Label(label="doijas oidaj oias")
        label.set_hexpand(True)
        label.set_wrap(True)
        box.append(label)
        self.set_child(box)

class MyApp(Gtk.Application):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.connect('activate', self.on_activate)
    
    def on_activate(self, app):
        self.win = MainWindow(application=app)
        self.win.present()

app = MyApp()
app.run()

That works fine if the window is vertically smaller than the picture, but else hexpand is ignored for the picture, judging by the increasing padding around it, and halign is also ignored, since it’s vertex 1 is not at (0,0) but starts to drift to the center of the allocated space.

wide

wide-and-high

Is this a bug? How do I get the desired behavior?

Hi,

It’s something expected. A GtkPicture with content-fit=SCALE_DOWN will preserve its aspect ration, so when it’s allocated more space in the Box then it will use it vertically then expand itself horizontally to respect the ratio.

A first step to mitigate this is to control the vertical expansion of the Box:

box.set_valign(Gtk.Align.CENTER)

To avoid the image getting too small, you can request a minimum height, here 50px:

image.set_size_request(-1, 50)
1 Like

Side note:

Please try to use enumeration names instead of integers.

If I look at this code, I can’t tell what “content-fit” is used without reading the doc:

image.set_content_fit(3)

Prefer something like this:

# using enum full name
image.set_content_fit(Gtk.ContentFit.SCALE_DOWN)
# using enum nickname
image.props.content_fit = 'scale-down'

For enum names, you can use this mapping table to find out the Python equivalent of C names.

1 Like

Hi @gwillems, first off all thank you for your comments.

My understanding is that halign=1 is respected by “glueing” the image to the left edge of the box and hexpand=False is respected by preventing the image size from changing; The aspect ratio can stay constant with those constraints, so I don’t see why content-fit would play a role.

It is arguable whether hexpand is being respected: The image size really didn’t expand in any of the depicted scenarios, but (for lack of a better word) the sub-container that the GtkBox gave to the image did, judging by the padding around the image. Using box.set_hexpand(0) doesn’t fix that, it seems that the GtkBox as the top level widget is being forced to stretch to full window dimensions.

I find it very strange that box.set_valign(Gtk.Align.START) does solve the two bullet points proposed in the top level post:

valign-start

Why is merely changing the valign of the box (so, its position in the Y axis) causing its children to fully reposition and resize? Shouldn’t that be transparent to them?

Veering off-topic, but ideal here would be some functionality like Motif’s XmForm widget, with which one could use XmN{top,left,bottom,right}Attachment to glue a widget to the edge of the form or to another widget, thus resulting in a more controlled layout, like in this example.

And, for someone who stumbles upon this post, that’s GtkGrid, even if you only need one dimension of it. No hexpand or halign is needed to get the expected behavior.

Not exactly.
expand properties are used when several widgets compete for sharing the allocation, to decide which one wins (or which ones share) the free space.

In your example, there is no competition vertically: the Box is alone, so will follow the default valign=FILL.
So the Picture will also fill the vertical space, and will proportionally expand horizontally to respect the ratio.

Using valign=CENTER or START on the Box will prevent it from using the full allocation, so its height will stick to the minimal requested childrens height (here it’s the label height), and the Picture will follow.

That said, I agree the way the Picture padding is computed is weird.
Once it reaches its original size, the image won’t grow further, but still tries to maintain its aspect ratio…

Maybe open an issue in GNOME’s gitlab to aks if the padding behavior is correct, i.e. if the aspect ratio computation should also involve the padding once the maximum size is reached.

1 Like

Do not use the issue tracker for questions: it’s what Discourse is for.

If you don’t get an answer here, you can join the GTK matrix channel.

Using the issue tracker for support wastes developer time for no good reason.

1 Like

Yes, sorry, fair point.
Thanks for the reminder :slight_smile:

Convinced that this is a bug, I filed a report in Gitlab (without any question).