Search code examples
cssgtkvala

Scale font size based on widget size in Gtk 3.0


I have a label in Gtk 3.0 (using Vala) that is styled with CSS. I'd like to scale the font size based on the widget's size, so that the font fills the widget/label but never gets too big.

What is the best way to do that using the CSS approach? Right now I'm setting the font to

font-size: 5em

but as far as I can tell, that does not scale with screen resolution.

For example, on a lower resolution screen, I get this (note the cut-off clock):

enter image description here

Previously we used an absolute scaling (see this diff for a surprisingly concise explanation) but we'd like to stick with CSS.

(more context if you're interested)


Solution

  • If you set a font size in ems or %, it will base itself on the default font size. The trick is to change the default font size according to the window size. Connect to the window's configure_event, and set a new default font size when the window is resized.

    Here's a simplified example:

    const string WINDOW_CSS_TEMPLATE = "#mywindow { font-size: %fpx; }";
    const string APPLICATION_CSS = "#mywindow .label { font-size: 5em; }";
    
    void main(string [] args) {
        Gtk.init(ref args);
    
        var win = new Gtk.Window();
        win.name = "mywindow";
        win.default_width = 800;
        win.default_height = 600;
        var label = new Gtk.Label("Some text");
        label.halign = Gtk.Align.END;
        label.valign = Gtk.Align.END;
        win.add(label);
        win.destroy.connect(Gtk.main_quit);
    
        var win_provider = new Gtk.CssProvider();
        Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),
            win_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
    
        var app_provider = new Gtk.CssProvider();
        try {
            app_provider.load_from_data(APPLICATION_CSS, -1);
        } catch (Error e) {
            Process.exit(1);
        }
        Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),
            app_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
    
        win.configure_event.connect((event) => {
            try {
                // Replace this with your desired calculation of the base font size
                var target_size = (double) event.height / 600.0 * 12.0;
                var css = WINDOW_CSS_TEMPLATE.printf(target_size);
                win_provider.load_from_data(css, -1);
            } catch (Error e) {
                Process.exit(1);
            }
            return Gdk.EVENT_PROPAGATE;
        });
    
        win.show_all();
        Gtk.main();
    }
    

    This only cares about the height of the window, so you'll get an unreadably tiny label if you resize the window to be much wider than it is high, but you can plug in whatever calculation works for you.