Hi!
As elaborated in Bottom sheet bottom bar with GtkPicture is broken (#995) · Issues · GNOME / libadwaita · GitLab I would like to display images with unknown sizes and aspect ratios (namely album covers) inside the bottom bar of a libadwaita bottom sheet. Previously this was possible by using a GtkPicture which automatically filled all the space available in the bottom bar. Unfortunately GtkPicture is now increasing the height of the bottom bar further. I’d like the height of the bottom bar to be automatically determined by the labels and the buttons in it and the image should then just take the available space and not request more.
In the issue mentioned above it was suggested to use a GtkImage at a fixed size. I’m not a fan of this idea as I think GTK generally does a great job at dynamically sizing the widgets and I really don’t want do use some magic fixed pixel sizes which could lead to unreadable text if someone changes the font size either through the large text option or manually.
Hi,
In the past I used to pack my GtkPictures as single child of a horizontal GtkBox. That breaks the weird width-for-height size ratio computation, allowing it to follow the height request of the other adjacent widgets.
Note that I don’t know if that still works with the latest allocation changes in gtk.
Thank you for the hint! Unfortunately it doesn’t work with the new GTK version.
This indeed was one of the things that got fixed.
I played around with custom a WIDTH_FOR_HEIGHT
widget. It seems like the problem could be solved with this but it’s very tedious to get this working with variable aspect ratios.
Oh… so that was relying on an unexpected corner-case behavior?
I’ll have to recheck for a proper solution then. Thanks for the info!
maybe you could use ConstraintLayout for it? i tried and got this:
#! /usr/bin/env -S vala --pkg libadwaita-1
class MyBar : Gtk.Widget {
Gtk.ConstraintLayout layout = new Gtk.ConstraintLayout();
Gtk.Widget pic = new Gtk.Image.from_file(Environment.get_user_special_dir(DOWNLOAD)+"/gnome-logo-text.svg");
Gtk.Widget btn = new Gtk.Button.from_icon_name("media-playback-start-symbolic") { tooltip_text = "Play" };
Gtk.Widget title = new Gtk.Label("The Foot") { halign = START, css_classes = { "title-4" } };
Gtk.Widget subtitle = new Gtk.Label("GNOME Foundation") { halign = START };
Gtk.Widget[] widgets { owned get { return { pic, btn, title, subtitle }; } }
construct {
foreach (var w in widgets)w.set_parent(this);
this.layout_manager = layout;
layout.add_constraints_from_description({
"H:|-[pic]-[title]-[btn]-|",
"H:|-[pic]-[subtitle]-[btn]-|",
"V:|-[title]-4-[subtitle]-|",
"V:|-[pic]-|",
"V:|-[btn]-|",
}, 8, 8, title: title, subtitle: subtitle, btn: btn, pic: pic);
layout.add_constraint(new Gtk.Constraint(btn, WIDTH, EQ, btn, HEIGHT, 1, 0, Gtk.ConstraintStrength.REQUIRED));
layout.add_constraint(new Gtk.Constraint(pic, WIDTH, EQ, pic, HEIGHT, 1, 0, Gtk.ConstraintStrength.REQUIRED));
layout.add_constraint(new Gtk.Constraint(title, START, EQ, subtitle, START, 1, 0, Gtk.ConstraintStrength.REQUIRED));
}
~MyBar() {
foreach (var w in widgets)w.unparent();
}
}
void main() {
// Environment.set_variable("GTK_DEBUG", "interactive", false);
var app = new Adw.Application("org.gnome.Example", 0);
app.activate.connect(() => {
var sheet = new Adw.BottomSheet() {
bottom_bar = new MyBar(),
};
var tview = new Adw.ToolbarView() {
content = sheet,
};
tview.add_top_bar(new Adw.HeaderBar());
var win = new Adw.ApplicationWindow(app) {
content = tview
};
win.present();
});
app.run();
}
Thank you very much! I think I can work with this.
Ok, I finally got around to this again. I translated your vala code to roughly equivalent python code. The only thing I left out for now should be the unparenting at the end. Unfortunately the bottom bar doesn’t show up but I also get no error messages. Does anyone have an idea what I could be doing wrong?
#!/usr/bin/python3
import gi
gi.require_version("Gtk", "4.0")
gi.require_version("Adw", "1")
from gi.repository import Gtk, GLib, Gdk, Adw
class MyBar(Gtk.Widget):
def __init(self):
super().__init__()
layout=Gtk.ConstraintLayout()
pic=Gtk.Image.new_from_file("gnome-logo-text.svg")
btn=Gtk.Button(icon_name="media-playback-start-symbolic", tooltip_text="Play")
title=Gtk.Label(text="The Foot", halign=Gtk.Align.START, css_class=["title-4"])
subtitle=Gtk.Label(text="GNOME Foundation", halign=Gtk.Align.START)
for w in (pic, btn, title, subtitle):
w.set_parent(self)
self.set_layout_manager(layout)
layout.add_constraints_from_description([
"H:|-[pic]-[title]-[btn]-|",
"H:|-[pic]-[subtitle]-[btn]-|",
"V:|-[title]-4-[subtitle]-|",
"V:|-[pic]-|",
"V:|-[btn]-|"], 8, 8, {"title": title, "subtitle": subtitle, "btn": btn, "pic": pic})
layout.add_constraint(Gtk.Constraint(btn, Gtk.ConstraintAttribute.WIDTH, Gtk.ConstraintRelation.EQ, btn, Gtk.ConstraintAttribute.HEIGHT, 1, 0, Gtk.ConstraintStrength.REQUIRED))
layout.add_constraint(Gtk.Constraint(pic, Gtk.ConstraintAttribute.WIDTH, Gtk.ConstraintRelation.EQ, pic, Gtk.ConstraintAttribute.HEIGHT, 1, 0, Gtk.ConstraintStrength.REQUIRED))
layout.add_constraint(Gtk.Constraint(title, Gtk.ConstraintAttribute.START, Gtk.ConstraintRelation.EQ, subtitle, Gtk.ConstraintAttribute.START, 1, 0, Gtk.ConstraintStrength.REQUIRED))
application=Adw.Application(application_id="com.example.picture")
def on_activate(application):
sheet=Adw.BottomSheet()
sheet.set_bottom_bar(MyBar())
view=Adw.ToolbarView()
view.add_top_bar(Adw.HeaderBar())
view.set_content(sheet)
# window
window=Adw.ApplicationWindow(application=application, default_width=360, default_height=360)
window.set_content(view)
window.present()
application.connect("activate", on_activate)
application.run()
i’m sorry for late reply
i also tried the code, and added some print statements, and it didn’t print anything, i noticed the method is called __init
instead of __init__
, so that’s why it didn’t run, i renamed it and it had some errors with property names and missing .new
when creating constrainsts, i changed that too, and it ran correctly, same as in vala
here is the full code with the changes:
#!/usr/bin/env python3
import gi
gi.require_version("Gtk", "4.0")
gi.require_version("Adw", "1")
from gi.repository import Gtk, GLib, Gdk, Adw
class MyBar(Gtk.Widget):
def __init__(self):
super().__init__()
layout=Gtk.ConstraintLayout()
pic=Gtk.Image.new_from_file("gnome-logo-text.svg")
btn=Gtk.Button(icon_name="media-playback-start-symbolic", tooltip_text="Play")
title=Gtk.Label(label="The Foot", halign=Gtk.Align.START, css_classes=["title-4"])
subtitle=Gtk.Label(label="GNOME Foundation", halign=Gtk.Align.START)
self.widgets = (pic, btn, title, subtitle)
for w in self.widgets:
w.set_parent(self)
self.set_layout_manager(layout)
layout.add_constraints_from_description([
"H:|-[pic]-[title]-[btn]-|",
"H:|-[pic]-[subtitle]-[btn]-|",
"V:|-[title]-4-[subtitle]-|",
"V:|-[pic]-|",
"V:|-[btn]-|"], 8, 8, {"title": title, "subtitle": subtitle, "btn": btn, "pic": pic})
layout.add_constraint(Gtk.Constraint.new(btn, Gtk.ConstraintAttribute.WIDTH, Gtk.ConstraintRelation.EQ, btn, Gtk.ConstraintAttribute.HEIGHT, 1, 0, Gtk.ConstraintStrength.REQUIRED))
layout.add_constraint(Gtk.Constraint.new(pic, Gtk.ConstraintAttribute.WIDTH, Gtk.ConstraintRelation.EQ, pic, Gtk.ConstraintAttribute.HEIGHT, 1, 0, Gtk.ConstraintStrength.REQUIRED))
layout.add_constraint(Gtk.Constraint.new(title, Gtk.ConstraintAttribute.START, Gtk.ConstraintRelation.EQ, subtitle, Gtk.ConstraintAttribute.START, 1, 0, Gtk.ConstraintStrength.REQUIRED))
def do_dispose(self):
# print('disposing')
for w in self.widgets:
w.unparent()
application=Adw.Application(application_id="com.example.picture")
def on_activate(application):
sheet=Adw.BottomSheet()
sheet.set_bottom_bar(MyBar())
view=Adw.ToolbarView()
view.add_top_bar(Adw.HeaderBar())
view.set_content(sheet)
# window
window=Adw.ApplicationWindow(application=application, default_width=360, default_height=360)
window.set_content(view)
window.present()
application.connect("activate", on_activate)
application.run()
tho i’m not sure if unparenting works correctly because do_dispose requires python3-gi 3.52 and i don’t have it yet, so i have a warning “MyBar still has children left” when closing the window, but it should probably work without warning on newer python packages
Thank you! What a dump mistake…
maybe python should warn about this, are identifiers that start with __
but not end with it actually used anywhere?
@monster said on matrix that it exits without a warning, thanks, so do_dispose
must work
You need to chain up:
def do_dispose(self):
for w in self.widgets:
w.unparent()
super().do_dispose()
Otherwise you’ll leak the rest of the instance memory.
are identifiers that start with
__
but not end with it actually used anywhere?
Yes, from PEP 8:
__double_leading_underscore
: when naming a class attribute, invokes name mangling (inside class FooBar,__boo
becomes_FooBar__boo
; see below).
For me it’s still exiting with the warning, even though I have version 3.52.3. Adding a print statement shows that do_dispose
isn’t run.
If the do_dispose()
implementation is not being called then it means something is holding a reference on the widget.