0

How can I write a custom Container in gtk-rs for GTK-3? I use gtk-rs 0.15.0 (to be compatible with the last GTK-3 compatible version of webkit2gtk). I couldn't find any reasonable documentation.

Reason behind this: I use a horizontally aligned Box layout, where I want a left component take roughly 2/3 window-width and the remainder component 1/3. "Roughly" meaning: In detail it's more complicated, but setting the sizes manually, also with hexpand set to false, leads to "wobbling" sizes, conflicting with the constantly changing contents sizes, all in all shaky behavior. Writing a custom container seems to be the cleanest way.

Is there any example code / project (e.g. GitHub ?) where a custom Container was written in gtk-rs for GTK-3?

1 Answers1

1

There's no need to write a custom container; to do what you described, you can simply use Grid.

Using Grid

As you probably know, the Grid container is made up of rows and columns. A single widget can take up multiple rows and columns. Thus, if you want one widget to span 2/3 of the window and the other to span 1/3 of it, you can use three columns of a Grid, and make the first widget cover two columns while the second widget covers just one.

In order to do this, you use the width and height arguments of Grid.attach(). For example, this widget will span two columns:

grid.attach(
    &widget,
    0, // X position (column)
    0, // Y position (row)
    2, // width (in columns)
    1  // height (in rows)
);

Now in order for the column proportions to be correct, you also need to set the columns homogeneous:

grid.set_column_homogeneous(true);

The same principles can be applied to rows too.

Example

All that being said, here is a simple working example with a Button and an Entry. The Button (on the left) takes up 2/3 of the width of the window, while the Entry (on the right) takes up only 1/3.

use gtk::prelude::*;
use gtk;

/// Create the window and all its widgets
fn create_window(app: &gtk::Application) {

    // The main window
    let window = gtk::ApplicationWindow::builder()
        .application(app)
        .title("Example")
        .build();
    window.set_position(gtk::WindowPosition::Center);

    // A Grid
    let grid = gtk::Grid::new();
    grid.set_column_homogeneous(true); // Makes sure the columns are proportional
    window.add(&grid);

    // A button that's 2 columns wide
    let button = gtk::Button::with_label("2/3 of the window");
    grid.attach(&button, 0, 0, 2, 1);

    // An entry that's only 1 column wide
    let entry = gtk::Entry::builder()
        .placeholder_text("1/3 of the window")
        .build();
    grid.attach(&entry, 2, 0, 1, 1);

    // Show all the widgets after creation
    window.show_all();
}

fn main() {

    // Create the application
    let app = gtk::Application::builder()
        .application_id("rust.example.app")
        .build();
    app.connect_activate(create_window);
    app.run();
}
Sylvester Kruin
  • 3,294
  • 5
  • 16
  • 39
  • Big thanks. This is already a huge improvement of all workarounds I found, but still not addressing the mentioned "more complicated" part, where the left part should only take ca. 2/3 width, till the 2/3 are equal to the height (the window is resizable). Can I build such a solution with the standard containers? – Jan Diederich May 23 '23 at 13:02
  • Hmm so you want the left side to expand, but when it is as wide as the height of the window, you want it to stop? Unfortunately I'm not sure how to do that. – Sylvester Kruin May 23 '23 at 13:05
  • I got even better results with nesting `Box` and `AspectFrame`, but that's still not really working, the custom `Container` would be the only really working solution. – Jan Diederich May 26 '23 at 10:58
  • 1
    Hmm okay. I'm sorry my answer didn't help! For what it's worth, the [gtk-rs repo](https://github.com/gtk-rs/gtk3-rs) has some [examples](https://github.com/gtk-rs/gtk3-rs/tree/master/examples), and the [Basic Subclass](https://github.com/gtk-rs/gtk3-rs/tree/master/examples/basic_subclass) example might help get you started on the right track. – Sylvester Kruin May 26 '23 at 11:46
  • Thanks, I knew the examples, but didn't recognize the "Basic Subclass" as a good starting point (thanks, really a good starting point). Also: I misunderstood the GtkPaned description, _that_ is the best _temporary_ solution for my problem. – Jan Diederich May 27 '23 at 19:06