Using GtkListBox with AdwTabView
Thanks to Gio.ListModel
it is surprisingly simple to use a Gtk.ListBox
as a vertical list of tabs for an Adw.TabView
.
The benefit over using a simple Gtk.Stack
is that Adw.TabView
supports standard shortcuts for switching view.
Here is a GJS example that should translate well to other languages. You can try this directly in Workbench.
// This snippet goes into Workbench UI Blueprint
using Gtk 4.0;
using Adw 1;
Box {
Gtk.ScrolledWindow {
width-request: 200;
Gtk.ListBox list_box {
selection-mode: browse;
}
}
Gtk.Separator {}
Adw.TabView tab_view {}
}
// This snippet goes into Workbench Code JavaScript
import Gtk from "gi://Gtk?version=4.0";
import Adw from "gi://Adw?version=1";
import GObject from "gi://GObject";
Gtk.init();
const tab_view = workbench.builder.get_object("tab_view");
const list_box = workbench.builder.get_object("list_box");
// Create a binding between the Gtk.ListBox and the Adw.TabView
list_box.bind_model(
tab_view.pages,
// This function will be called for every new Adw.TabPage
(tab_page) => {
return buildTabRow(tab_page);
},
);
list_box.connect("row-selected", (self, row) => {
tab_view.set_selected_page(row.tab_page);
});
tab_view.connect("notify::selected-page", (self, page) => {
list_box.select_row(tab_view.selected_page.list_box_row);
});
// Add some Adw.TabPage and let the binding do the rest
for (let i = 1; i < 11; i++) {
const title = `hello ${i}`;
const tab_page = tab_view.append(
new Adw.StatusPage({
title,
hexpand: true,
}),
);
tab_page.title = title;
}
// You probably should use a custom widget
// but this will do it for the purpose of this example
function buildTabRow(tab_page) {
const list_box_row = new Gtk.ListBoxRow({
selectable: true,
});
list_box_row.tab_page = tab_page;
const label = new Gtk.Label();
list_box_row.set_child(label);
tab_page.list_box_row = list_box_row;
tab_page.bind_property(
"title",
label,
"label",
GObject.BindingFlags.SYNC_CREATE,
);
return list_box_row;
}