Привет, Хабр!
Разметку для Gtk-приложений можно создавать несколькими способами. Это можно сделать при помощи средств самого языка программирования, на котором пишется программа. Или же применить визуальный конструктор, типа Cambalache, который, в свою очередь, создаст специальный ui-файл в формате XML.
Blueprint — это язык разметки, а также компилятор, специально созданный для приложений написанных на Gtk4. С официальной документацией по этому проекту можно ознакомиться на этом сайте. Если программа использует ui-файлы для пользовательского интерфейса, то разработчику нужно будет лишь заменить эти файлы на blp-файлы и немного дополнить сборочные сценарии. Но об этом чуть позже.
Рассмотрим как применить этот инструмент на примере простой программки для расчета даты католической Пасх��. Программа использует для расчета даты так называемый алгоритм Гаусса. Написано приложение на языке Vala с использованием библиотек Gtk4 и libadwaita. Репозиторий приложения находится здесь. Выглядит оно примерно таким образом:

Весь интерфейс построен на контейнерах Gtk.Box, которые вложены один в другой. Значок очистки в поле для ввода номера года добавляется при помощи vala-кода:
year.set_icon_from_icon_name (Gtk.EntryIconPosition.SECONDARY, "edit-clear-symbolic");
year.icon_press.connect ((pos, event) => {
year.set_text("");
year.grab_focus();
});Файл интерфейса на XML для этого приложения выглядит так:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<template class="ValaGtkTemplateWindow" parent="AdwApplicationWindow">
<property name="title">Vala & GTK Template</property>
<property name="default-height">300</property>
<child>
<object class="GtkBox">
<property name="orientation">1</property>
<child>
<object class="AdwHeaderBar"></object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">1</property>
<property name="vexpand">true</property>
<property name="hexpand">true</property>
<property name="margin-top">6</property>
<property name="margin-end">6</property>
<property name="margin-start">6</property>
<property name="margin-bottom">6</property>
<child>
<object class="GtkBox">
<property name="orientation">0</property>
<property name="spacing">6</property>
<property name="hexpand">true</property>
<child>
<object class="GtkBox">
<property name="orientation">1</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="label">year:</property>
<property name="xalign">0</property>
</object>
</child>
<child>
<object class="GtkEntry" id="year">
<property name="hexpand">true</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="calculate">
<property name="label">CALCULATE</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel" id="result">
<property name="vexpand">true</property>
<property name="valign">3</property>
<style>
<class name="title-1"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>Согласитесь, что это не совсем удобный формат для ручного редактирования. А вот тот же файл, но уже в формате Blueprint:
using Gtk 4.0;
using Adw 1;
template ValaGtkTemplateWindow : Adw.ApplicationWindow {
title: "Vala & GTK Template";
default-height: 300;
Box {
orientation: vertical;
Adw.HeaderBar {}
Box {
orientation: vertical;
vexpand: true;
hexpand: true;
margin-top: 6;
margin-end: 6;
margin-start: 6;
margin-bottom: 6;
Box {
orientation: horizontal;
spacing: 6;
hexpand: true;
Box {
orientation: vertical;
spacing: 6;
Label {
label: "year:";
xalign: 0;
}
Entry year {
hexpand: true;
}
}
Button calculate {
label: "CALCULATE";
}
}
Label result {
vexpand: true;
valign: center;
styles ["title-1"]
}
}
}
}Так уже гораздо лучше. Проще разобраться, где какой компонент расположен, где он начинается и где заканчивается. Как это все работает? К проекту подключается программа blueprint-compiler. Ее задача заключается в том, чтобы из файла в формате blp создать ui-файл. Для этого в файле meson.build нужно прописать:
blueprints = custom_target (
'blueprints',
input: files (
'data/resources/window.blp',
),
output: '.',
command: [ find_program ('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@' ]
)И еще не забыть в разделе ресурсов в том же файле указать:
dependencies: blueprintsТаким образом, один файл подменяется другим. Там, где указывается путь до ui-файла, в частности, в window.vala и gresource.xml, ничего изменять не нужно. Если ваш проект использует упаковку flatpak, то в манифест необходимо добавить следующий модуль:
{
"name": "blueprint-compiler",
"buildsystem": "meson",
"sources": [
{
"type": "git",
"url": "https://gitlab.gnome.org/jwestman/blueprint-compiler",
"branch": "main"
}
]
}Для работы с Blueprint рекомендуется использовать Workbench или GNOME Builder. Обе программы поддерживают подсветку синтаксиса blp-файлов, а Workbench вдобавок имеет встроенную функцию предварительного просмотра дизайна интерфейса.
