Привет, Хабр!
Разметку для 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 вдобавок имеет встроенную функцию предварительного просмотра дизайна интерфейса.