Привет, Хабр!

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