Skip to main content
Ir para o conteúdo

Kirigami com o Rust

Crie seu primeiro aplicativo Kirigami com o Rust

Instalando o Kirigami

Antes de começar, precisaremos instalar o Kirigami e o Rust em nossa máquina.

logo of Linux operating system ManjaroManjarologo of Linux operating system Arch LinuxArch
sudo pacman -S cargo cmake extra-cmake-modules kirigami breeze qqc2-desktop-style
logo of Linux operating system openSUSEOpenSUSE
sudo zypper install cargo cmake kf6-extra-cmake-modules kf6-kirigami-devel qt6-quickcontrols2-devel kf6-qqc2-desktop-style
logo of Linux operating system FedoraFedora
sudo dnf install cargo cmake extra-cmake-modules kf6-kirigami2-devel kf6-qqc2-desktop-style

Mais informações sobre outras distribuições podem ser encontradas aqui.

Estrutura do projeto

Primeiro, criamos a pasta do nosso projeto (você pode usar os comandos abaixo). Vamos chamá-la de kirigami_rust/. Esta será a estrutura do projeto:

kirigami_rust/
├── CMakeLists.txt
├── Cargo.toml
├── build.rs
├── org.kde.kirigami_rust.desktop
└── src/
    ├── main.rs
    └── qml/
        └── Main.qml

Este projeto usará o CMake para chamar o Cargo, que por sua vez compilará o projeto.

O projeto será chamado de kirigami_rust e gerará um executável chamado kirigami_hello.

org.kde.kirigami_rust.desktop

O objetivo principal dos arquivos de entrada de desktop é exibir seu aplicativo no inicializador de aplicativos do Linux. Outro motivo para tê-los é para ter ícones de janela no Wayland, pois eles são necessários para informar ao compositor que "esta janela combina com este ícone".

Ele deve seguir um esquema de nomenclatura DNS reverso seguido pela extensão .desktop, como org.kde.kirigami_rust.desktop:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
[Desktop Entry]
Name=Kirigami Tutorial in Rust
Name[ca]=Guia d'aprenentatge del Kirigami en Rust
Name[es]=Tutorial de Kirigami en Rust
Name[fr]=Tutoriel pour Kirigami en Rust
Name[it]=Esercitazione di Kirigami in Rust
Name[nl]=Kirigami handleiding in Rust
Name[pt_BR]=Tutorial do Kirigami em Rust
Name[sl]=Učbenik Kirigami v Rustu
Name[sv]=Kirigami-handledning i Rust
Name[tr]=Rust ile Kirigami Öğreticisi
Name[uk]=Підручник з Kirigami для Rust
Exec=kirigami_hello
Icon=kde
Type=Application
Terminal=false
Categories=Utility

CMakeLists.txt

O arquivo CMakeLists.txt será usado para executar o Cargo e instalar os arquivos necessários junto com nossa aplicação. Ele também oferece certos recursos de qualidade de vida, como garantir que o Kirigami seja instalado durante a compilação e sinalizar às distribuições Linux para instalarem as dependências necessárias com a aplicação.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cmake_minimum_required(VERSION 3.28)

project(kirigami_rust)

find_package(ECM 6.0 REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
include(KDEInstallDirs)
include(ECMUninstallTarget)

include(ECMFindQmlModule)
ecm_find_qmlmodule(org.kde.kirigami REQUIRED)
find_package(KF6 REQUIRED COMPONENTS QQC2DesktopStyle)

add_custom_target(kirigami_rust
    ALL
    COMMAND cargo build --target-dir ${CMAKE_CURRENT_BINARY_DIR}
)

install(
    PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/debug/kirigami_hello
    DESTINATION ${KDE_INSTALL_BINDIR}
)

install(FILES org.kde.kirigami_rust.desktop DESTINATION ${KDE_INSTALL_APPDIR})

A primeira coisa que fazemos é adicionar os Módulos Extras do CMake (ECM) do KDE ao nosso projeto para que possamos usar o ecm_find_qml_module para verificar se o Kirigami está instalado ao tentar compilar o aplicativo e, caso contrário, falhar imediatamente. Outro recurso útil do ECM é o ECMUninstallTarget, que permite desinstalar facilmente o aplicativo com o CMake, se desejado.

Também usamos o find_package() do CMake para garantir que tenhamos o qqc2-desktop-style, o estilo QML do KDE para a área de trabalho. Este é um dos dois motivos pelos quais usamos o CMake neste tutorial.

Normalmente, projetos Rust são compilados com o Cargo, e não será diferente aqui. Criamos um destino que simplesmente executará o Cargo quando executado e o marcamos com ALL para que ele seja compilado por padrão. O Cargo compilará o executável dentro do diretório binário do CMake (normalmente build/).

Para mais informações sobre o CMake, alvos e o diretório binário, consulte Construindo software KDE manualmente.

Depois disso, simplesmente instalamos o executável kirigami_rust gerado pelo Cargo no diretório binário e o instalamos no BINDIR, que geralmente é /usr/bin, /usr/local/bin ou ~/.local/bin. Também instalamos o arquivo desktop necessário no APPDIR, que geralmente é /usr/share/applications ou ~/.local/share/applications. Este é o segundo motivo pelo qual usamos o CMake neste tutorial.

Para obter mais informações sobre onde o software KDE é instalado, consulte Compilando o software KDE manualmente: A etapa de instalação.

Agora que cuidamos do CMake, vamos dar uma olhada nos arquivos com os quais passaremos a maior parte do nosso tempo trabalhando.

Cargo.toml

Em seguida, temos um Cargo.toml muito simples:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[package]
name = "kirigami_hello"
version = "0.1.0"
authors = [ "Konqi the Konqueror <konqi@kde.org>" ]
edition = "2021"
license = "GPLv3"

[dependencies]
cxx = "1.0.95"
cxx-qt = "0.7"
cxx-qt-lib = { version="0.7", features = ["qt_full"] }
cxx-qt-lib-extras = "0.7"

[build-dependencies]
# The link_qt_object_files feature is required for statically linking Qt 6.
cxx-qt-build = { version = "0.7", features = [ "link_qt_object_files" ] }

Ele consiste em metadados do projeto e uma lista de dependências que serão extraídas automaticamente pelo Cargo, ou seja, cxx e cxx-qt, que são necessárias para executar aplicativos Qt escritos em Rust.

build.rs

Enquanto em C++ você normalmente registraria elementos QML com QML_ELEMENT e ecm_add_qml_module usando [registro declarativo](https://www.qt.io/blog/qml-type-registration-in-qt -5.15), com Rust você precisará declará-lo em um arquivo script de compilação build.rs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
use cxx_qt_build::{CxxQtBuilder, QmlModule};

fn main() {
    CxxQtBuilder::new()
        .qml_module(QmlModule {
            uri: "org.kde.tutorial",
            qml_files: &["src/qml/Main.qml"],
            rust_files: &["src/main.rs"],
            ..Default::default()
        })
        .build();
}

Isso é necessário para disponibilizar o arquivo QML no ponto de entrada do nosso aplicativo, main.rs.

src/main.rs

O arquivo kirigami_rust/src/main.rs inicializa o projeto e então carrega o arquivo QML, que consistirá na interface do usuário do aplicativo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#[cxx_qt::bridge]
mod ffi {
    extern "RustQt" {
        #[qobject]
        type DummyQObject = super::DummyRustStruct;
    }
}

#[derive(Default)]
pub struct DummyRustStruct;

use cxx_qt_lib::{QGuiApplication, QQmlApplicationEngine, QQuickStyle, QString, QUrl};
use cxx_qt_lib_extras::QApplication;
use std::env;

fn main() {
    let mut app = QApplication::new();
    let mut engine = QQmlApplicationEngine::new();

    // To associate the executable to the installed desktop file
    QGuiApplication::set_desktop_file_name(&QString::from("org.kde.kirigami_rust"));
    // To ensure the style is set correctly
    let style = env::var("QT_QUICK_CONTROLS_STYLE");
    if style.is_err() {
        QQuickStyle::set_style(&QString::from("org.kde.desktop"));
    }

    if let Some(engine) = engine.as_mut() {
        engine.load(&QUrl::from("qrc:/qt/qml/org/kde/tutorial/src/qml/Main.qml"));
    }

    if let Some(app) = app.as_mut() {
        app.exec();
    }
}

A primeira parte, marcada com a macro Rust #[cxx_qt::bridge], apenas cria um QObject fictício a partir de uma struct Rust fictícia. Isso é necessário apenas para concluir o uso de QmlModule no script de compilação anterior build.rs. Isso terá um papel maior em um tutorial futuro que ensinará como expor código Rust ao QML, mas, por enquanto, você pode ignorá-lo.

Depois disso começa a parte importante:

As linhas 12-13 importam as bibliotecas Qt necessárias expostas por meio do cxx-qt.

Primeiro, criamos uma nova instância de QApplication e, em seguida, realizamos algumas integrações nas linhas 20 a 26.

Em seguida vem a parte que realmente cria a janela do aplicativo:

28
29
30
    if let Some(engine) = engine.as_mut() {
        engine.load(&QUrl::from("qrc:/qt/qml/org/kde/tutorial/src/qml/Main.qml"));
    }

A URL longa qrc:/qt/qml/org/kde/tutorial/src/qml/Main.qml corresponde ao arquivo Main.qml de acordo com o Sistema de Recursos Qt e segue este esquema: <prefixo_do_recurso><URI_de_importação><diretório_QML><arquivo>.

Em outras palavras: o prefixo de recurso padrão qrc:/qt/qml/ + o URI de importação org/kde/tutorial (definido em build.rs, separado por barras em vez de pontos) + o diretório QML src/qml/ + o arquivo QML Main.qml.

src/qml/Main.qml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Includes relevant modules used by the QML
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls as Controls
import org.kde.kirigami as Kirigami

// Provides basic features needed for all kirigami applications
Kirigami.ApplicationWindow {
    // Unique identifier to reference this object
    id: root

    width: 400
    height: 300

    // Window title
    title: "Hello World"

    // Set the first page that will be loaded when the app opens
    // This can also be set to an id of a Kirigami.Page
    pageStack.initialPage: Kirigami.Page {
        Controls.Label {
            // Center label horizontally and vertically within parent object
            anchors.centerIn: parent
            text: "Hello World!"
        }
    }
}

É aqui que manipularemos o frontend do nosso aplicativo.

Se você conhece um pouco de Javascript, grande parte do QML lhe parecerá familiar (embora tenha suas peculiaridades). A documentação do Qt possui um vasto material sobre esta linguagem, caso você queira experimentar algo por conta própria. Ao longo destes tutoriais, concentraremos grande parte da nossa atenção em nosso código QML, onde podemos usar o Kirigami para aproveitá-lo ao máximo.

Por enquanto, vamos nos concentrar em Main.qml. Primeiro, importamos alguns módulos importantes:

  • QtQuick, a biblioteca padrão usada em aplicativos QML.
  • QtQuick Controls, que fornece uma série de controles padrão que podemos usar para tornar nossos aplicativos interativos.
  • QtQuick Layouts, que fornece ferramentas para posicionar componentes na janela do aplicativo.
  • Kirigami, que fornece uma série de componentes adequados para criar aplicativos que funcionam em dispositivos de diferentes formatos e tamanhos.

Chegamos então ao nosso elemento base, Kirigami.ApplicationWindow, que fornece alguns recursos básicos necessários para todos os aplicativos Kirigami. Esta é a janela que conterá cada uma das nossas páginas, as principais seções da nossa interface do usuário.

Em seguida, definimos a propriedade id da janela como "root". IDs são úteis porque nos permitem referenciar exclusivamente um componente, mesmo que tenhamos vários do mesmo tipo.

Também definimos a propriedade title da janela como "Hello World".

Em seguida, definimos a primeira página da nossa pilha de páginas. A maioria dos aplicativos Kirigami é organizada como uma pilha de páginas, cada página contendo componentes relacionados adequados a uma tarefa específica. Por enquanto, estamos mantendo a simplicidade e nos atendo a uma única página. pageStack é uma pilha de páginas inicialmente vazia fornecida por Kirigami.ApplicationWindow, e com pageStack.initialPage: Kirigami.Page {...}, definimos a primeira página apresentada ao carregar o aplicativo para uma Kirigami.Page. Esta página conterá todo o nosso conteúdo.

Por fim, incluímos em nossa página um Controls.Label que nos permite inserir texto em nossa página. Usamos anchors.centerIn:parent para centralizar nosso rótulo horizontal e verticalmente dentro do nosso elemento pai. Neste caso, o componente pai do nosso rótulo é Kirigami.Page. A última coisa que precisamos fazer é definir seu texto: text: "Hello World!".

Compilando e instalando o aplicativo

Você deverá encontrar o executável gerado kirigami_hello em build/debug/kirigami_hello e poderá executá-lo diretamente ou com cargo run, mas ele não terá um ícone do Windows. Para resolver isso, instalaremos o aplicativo primeiro.

Execute o seguinte:

cmake -B build --install-prefix ~/.local
cmake --build build/
cmake --install build/

Com o primeiro comando, o CMake irá procurar por Kirigami e qqc2-desktop-style.

Com o segundo comando, o CMake compilará o alvo kirigami_rust, que apenas chama cargo build --target-dir build/. Esta etapa levará um tempo para ser concluída, mas na próxima vez que você repetir o segundo comando do CMake, será mais rápido ou você não precisará compilar.

Na terceira etapa, o CMake instalará o executável kirigami_hello em ~/.local/bin/kirigami_hello e o arquivo desktop em ~/.local/share/applications, e uma nova entrada chamada "Tutorial de Kirigami em Rust" aparecerá no seu menu.

Abra a entrada do menu e pronto! Agora você verá seu primeiro aplicativo Kirigami aparecer diante dos seus olhos.

Captura de tela do aplicativo Kirigami gerado

Para executar o novo aplicativo QML no modo para dispositivo móvel, você pode usar QT_QUICK_CONTROLS_MOBILE=1:

QT_QUICK_CONTROLS_MOBILE=1 kirigami_hello

Se você compilou o projeto manualmente com o CMake e, por algum motivo, deseja desinstalar o projeto, você pode executar:

cmake --build build/ --target uninstall