Skip to content

Instantly share code, notes, and snippets.

@dmitry-osin
Created May 3, 2025 03:58
Show Gist options
  • Save dmitry-osin/4e5ed28b0f70d4b279021357396beef0 to your computer and use it in GitHub Desktop.
Save dmitry-osin/4e5ed28b0f70d4b279021357396beef0 to your computer and use it in GitHub Desktop.
Полная шпаргалка по языку разметки Slint

Полная шпаргалка по языку разметки Slint

Основы Slint

Структура файла Slint

import { Button } from "std-widgets.slint";

export component MyApp inherits Window {
    width: 400px;
    height: 300px;
    
    Text {
        text: "Привет, мир!";
        font-size: 24px;
        color: blue;
    }
    
    Button {
        text: "Нажми меня";
        clicked => { /* обработчик события */ }
    }
}

Импорт компонентов

import { Component1, Component2 } from "library.slint";
import * as Lib from "another-library.slint";

Компоненты

Создание компонента

export component MyComponent {
    // свойства и элементы
    width: 100px;
    height: 100px;
    
    Text {
        text: "Содержимое компонента";
    }
}

Наследование

component ChildComponent inherits ParentComponent {
    // дополнительные свойства и элементы
    property<string> additional-text: "Дополнительный текст";
}

Свойства

Объявление свойств

export component Example {
    // Базовые типы
    property<string> text: "Значение по умолчанию";
    property<int> count: 0;
    property<float> opacity: 1.0;
    property<bool> is-enabled: true;
    
    // Сложные типы
    property<color> bg-color: #3498db;
    property<length> width: 100px;
    property<duration> animation-duration: 300ms;
    property<brush> my-brush: @linear-gradient(90deg, #ff0000, #00ff00);
    
    // Структуры и массивы
    property<{x: int, y: int}> position: {x: 0, y: 0};
    property<[int]> numbers: [1, 2, 3, 4, 5];
}

Двусторонняя привязка

property<int> counter <=> parent.counter;

Вычисляемые свойства

property<string> full-name: first-name + " " + last-name;

Элементы интерфейса

Rectangle

Rectangle {
    width: 100px;
    height: 100px;
    color: red;
    border-radius: 8px;
    border-width: 1px;
    border-color: black;
    
    // Градиентная заливка
    background: @linear-gradient(90deg, #ff0000, #00ff00);
    
    // Тень
    drop-shadow: 2px 2px 5px #00000080;
    
    // Вложенные элементы
    Text {
        text: "Текст внутри прямоугольника";
        color: white;
    }
}

Text

Text {
    text: "Пример текста";
    font-size: 16px;
    font-weight: bold;
    font-family: "Arial";
    color: black;
    horizontal-alignment: center;
    vertical-alignment: center;
    overflow: elide;
    wrap: word-wrap;
    letter-spacing: 1px;
}

Image

Image {
    source: @image-url("path/to/image.png");
    width: 100px;
    height: 100px;
    image-fit: contain;  // contain, cover, fill
    colorize: #ff0000;   // тонирование изображения
    source-clip-x: 0;
    source-clip-y: 0;
    source-clip-width: 50%;
    source-clip-height: 50%;
}

TextInput

TextInput {
    text: "Редактируемый текст";
    font-size: 14px;
    placeholder-text: "Введите текст...";
    has-focus: true;
    enabled: true;
    read-only: false;
    input-type: text;  // text, password, number
    selection-foreground-color: white;
    selection-background-color: blue;
}

Button

Button {
    text: "Нажми меня";
    icon: @image-url("icon.png");
    enabled: true;
    primary: true;  // основная кнопка
    
    clicked => {
        debug("Кнопка нажата");
    }
}

CheckBox

CheckBox {
    text: "Выбери меня";
    checked: false;
    enabled: true;
    
    toggled => {
        debug("Состояние изменено: " + self.checked);
    }
}

Slider

Slider {
    width: 200px;
    minimum: 0;
    maximum: 100;
    value: 50;
    orientation: horizontal;  // horizontal, vertical
    
    changed => {
        debug("Значение изменено: " + self.value);
    }
}

ComboBox

ComboBox {
    model: ["Опция 1", "Опция 2", "Опция 3"];
    current-index: 0;
    enabled: true;
    
    selected => {
        debug("Выбрана опция: " + self.current-value);
    }
}

ScrollView

ScrollView {
    width: 300px;
    height: 200px;
    viewport-width: 500px;
    viewport-height: 400px;
    
    Rectangle {
        width: 500px;
        height: 400px;
        
        for i in 10: Rectangle {
            y: i * 40px;
            width: 100%;
            height: 30px;
            color: i % 2 == 0 ? #e0e0e0 : #f0f0f0;
            
            Text {
                text: "Элемент " + i;
            }
        }
    }
}

Flickable

Flickable {
    width: 300px;
    height: 300px;
    viewport-width: 600px;
    viewport-height: 600px;
    interactive: true;
    
    Rectangle {
        width: 600px;
        height: 600px;
        color: blue;
    }
}

Path

Path {
    width: 100px;
    height: 100px;
    commands: "M 10 10 L 90 10 L 90 90 L 10 90 Z";
    stroke: black;
    stroke-width: 2px;
    fill: red;
}

Контейнеры и компоновка

VerticalLayout

VerticalLayout {
    spacing: 10px;
    alignment: center;
    padding: 10px;
    
    Text { text: "Первый элемент"; }
    Text { text: "Второй элемент"; }
    Rectangle { height: 50px; color: blue; }
}

HorizontalLayout

HorizontalLayout {
    spacing: 10px;
    alignment: space-between;
    padding-left: 5px;
    padding-right: 5px;
    
    Rectangle { width: 50px; height: 50px; color: red; }
    Rectangle { width: 50px; height: 50px; color: green; }
    Rectangle { width: 50px; height: 50px; color: blue; }
}

GridLayout

GridLayout {
    spacing: 5px;
    
    Row {
        Rectangle { color: red; }
        Rectangle { color: green; }
        Rectangle { color: blue; }
    }
    
    Row {
        Rectangle { color: yellow; }
        Rectangle { color: cyan; }
        Rectangle { color: magenta; }
    }
}

TableLayout

TableLayout {
    Row {
        Text { text: "Имя"; }
        Text { text: "Возраст"; }
        Text { text: "Город"; }
    }
    
    Row {
        Text { text: "Иван"; }
        Text { text: "25"; }
        Text { text: "Москва"; }
    }
    
    Row {
        Text { text: "Мария"; }
        Text { text: "30"; }
        Text { text: "Санкт-Петербург"; }
    }
}

События и обработчики

Определение обработчика события

export component Button {
    callback clicked();
    
    Rectangle {
        // ...
        TouchArea {
            clicked => { root.clicked(); }
        }
    }
}

Использование обработчика

Button {
    clicked => {
        counter += 1;
        debug("Счетчик: " + counter);
    }
}

Передача параметров в обработчик

export component ItemList {
    callback item-selected(int);
    
    for item[i] in items: Rectangle {
        TouchArea {
            clicked => { root.item-selected(i); }
        }
    }
}

Состояния и анимации

Состояния

Rectangle {
    color: white;
    
    states [
        pressed when touch-area.pressed: {
            color: blue;
            scale: 0.9;
        }
        hover when touch-area.has-hover: {
            color: lightblue;
        }
        disabled when !enabled: {
            opacity: 0.5;
        }
    ]
    
    TouchArea { }
}

Анимации

Rectangle {
    color: white;
    
    // Анимация отдельных свойств
    animate color { duration: 250ms; easing: ease-in-out; }
    animate scale { duration: 150ms; easing: ease; }
    
    // Анимация для состояний
    states [
        active when is-active: {
            color: blue;
            animate color { duration: 500ms; }
        }
    ]
}

Сложные анимации

Rectangle {
    x: 0px;
    
    animate x {
        duration: 2s;
        iteration-count: infinite;
        easing: cubic-bezier(0.42, 0, 0.58, 1);
        alternate: true;
        
        // Ключевые кадры
        keyframes: [
            { value: 0px; easing: ease-in; },
            { value: 100px; easing: ease-out; },
            { value: 50px; }
        ];
    }
}

Циклы и условия

Циклы

// Простой цикл
for i in 5: Rectangle {
    y: i * 30px;
    height: 20px;
    color: Colors.darker(blue, i / 5);
}

// Цикл по модели данных
for item[i] in model: Rectangle {
    color: item.color;
    Text { text: item.text + " (" + i + ")"; }
}

Условия

// Условный элемент
if condition: Rectangle {
    // отображается только если condition == true
}

// Условное свойство
Rectangle {
    visible: condition;  // альтернативный способ
    color: is-active ? blue : gray;  // тернарный оператор
}

// Условие с else
if condition {
    Rectangle { color: green; }
} else {
    Rectangle { color: red; }
}

Модели данных

Определение структуры

struct TodoItem {
    text: string,
    completed: bool,
}

Использование модели

export component TodoList {
    property<[TodoItem]> items: [
        { text: "Купить молоко", completed: false },
        { text: "Выгулять собаку", completed: true },
    ];
    
    VerticalLayout {
        for item[i] in items: HorizontalLayout {
            CheckBox { 
                checked: item.completed;
                toggled => { 
                    items[i].completed = self.checked;
                }
            }
            Text { 
                text: item.text;
                text-decoration: item.completed ? line-through : none;
            }
        }
    }
}

Динамическое обновление модели

export component TodoApp {
    property<[TodoItem]> items: [];
    property<string> new-item-text: "";
    
    function add-item() {
        items = [... items, { text: new-item-text, completed: false }];
        new-item-text = "";
    }
    
    function remove-item(index: int) {
        items = [... items.slice(0, index), ... items.slice(index + 1)];
    }
}

Геометрия и позиционирование

Абсолютное позиционирование

Rectangle {
    x: 10px;
    y: 20px;
    width: 100px;
    height: 50px;
}

Относительное позиционирование

Rectangle {
    x: parent.width / 2 - self.width / 2;  // центрирование по горизонтали
    y: parent.height / 2 - self.height / 2;  // центрирование по вертикали
}

Привязки (Anchors)

Rectangle {
    width: 100px;
    height: 100px;
    
    Rectangle {
        x: 0px;
        y: 0px;
        width: parent.width / 2;
        height: parent.height / 2;
    }
    
    Rectangle {
        x: parent.width - self.width;
        y: parent.height - self.height;
        width: 50px;
        height: 50px;
    }
}

Z-порядок (наложение элементов)

Rectangle {
    z: 0;
    color: blue;
}

Rectangle {
    z: 1;  // будет отображаться поверх предыдущего прямоугольника
    color: red;
    opacity: 0.5;
}

Фокус и клавиатурное управление

Управление фокусом

FocusScope {
    key-pressed(event) => {
        if (event.text == "Enter") {
            submit();
            return accept;
        }
        return reject;
    }
    
    key-released(event) => {
        debug("Клавиша отпущена: " + event.text);
        return accept;
    }
}

Порядок табуляции

TextInput {
    focus-on-tab: true;
    tab-order: 1;
}

TextInput {
    focus-on-tab: true;
    tab-order: 2;
}

Горячие клавиши

FocusScope {
    key-pressed(event) => {
        if (event.modifiers.control && event.text == "s") {
            save-document();
            return accept;
        }
        return reject;
    }
}

Локализация

Использование переводов

import { translations } from "translations.slint";

Text {
    text: translations.welcome-message;
}

Определение переводов

// translations.slint
export global translations {
    property<string> welcome-message: "Добро пожаловать";
    property<string> save-button: "Сохранить";
    property<string> cancel-button: "Отмена";
}

Форматирование чисел и дат

Text {
    text: Format.decimal(value, 2);  // 2 знака после запятой
}

Text {
    text: Format.date(date, "dd.MM.yyyy");
}

Text {
    text: Format.duration(duration, "mm:ss");
}

Темы и стили

Определение темы

global Theme {
    property<color> primary-color: #3498db;
    property<color> secondary-color: #2ecc71;
    property<color> background-color: white;
    property<color> text-color: black;
    property<length> spacing: 8px;
    property<length> border-radius: 4px;
    property<length> font-size: 14px;
}

Использование темы

Rectangle {
    color: Theme.background-color;
    border-radius: Theme.border-radius;
    
    Text {
        color: Theme.text-color;
        font-size: Theme.font-size;
    }
}

Переключение тем

global Themes {
    property<{
        primary: color,
        background: color,
        text: color,
    }> current: dark;
    
    property<{
        primary: color,
        background: color,
        text: color,
    }> light: {
        primary: #3498db,
        background: white,
        text: black,
    };
    
    property<{
        primary: color,
        background: color,
        text: color,
    }> dark: {
        primary: #2980b9,
        background: #2c3e50,
        text: white,
    };
    
    function toggle-theme() {
        current = current == light ? dark : light;
    }
}

// Использование
Rectangle {
    color: Themes.current.background;
    
    Text {
        color: Themes.current.text;
    }
    
    Button {
        text: "Переключить тему";
        clicked => { Themes.toggle-theme(); }
    }
}

Пользовательские функции

Определение функций

export component Example {
    function calculate-area(width: length, height: length) -> length {
        return width * height;
    }
    
    function is-valid-input() -> bool {
        return input-text != "";
    }
    
    function increment-counter() {
        counter += 1;
    }
    
    property<int> counter: 0;
    property<string> input-text: "";
}

Вызов функций

Rectangle {
    width: 100px;
    height: 50px;
    
    property<length> area: calculate-area(self.width, self.height);
    
    Button {
        text: "Увеличить счетчик";
        clicked => { increment-counter(); }
        enabled: is-valid-input();
    }
}

Обработка жестов и сенсорных событий

Жесты

TouchArea {
    pointer-event(event) => {
        if (event.kind == pressed) {
            debug("Нажатие в точке: " + event.x + ", " + event.y);
        } else if (event.kind == released) {
            debug("Отпускание в точке: " + event.x + ", " + event.y);
        }
        accept
    }
    
    moved => {
        debug("Перемещение: " + self.mouse-x + ", " + self.mouse-y);
    }
}

Перетаскивание (Drag & Drop)

Rectangle {
    property<bool> dragging;
    property<length> drag-start-x;
    property<length> drag-start-y;
    
    TouchArea {
        pressed => {
            root.dragging = true;
            root.drag-start-x = self.mouse-x;
            root.drag-start-y = self.mouse-y;
        }
        
        moved => {
            if (root.dragging) {
                root.x += self.mouse-x - root.drag-start-x;
                root.y += self.mouse-y - root.drag-start-y;
            }
        }
        
        released => {
            root.dragging = false;
        }
    }
}

Мультитач

TouchArea {
    property<bool> multi-touch-enabled: true;
    
    pointer-event(event) => {
        if (event.kind == pressed) {
            debug("Нажатие пальца " + event.pointer-id);
        }
        accept
    }
}

Таймеры

Использование таймеров

export component Timer {
    property<bool> running: false;
    property<duration> interval: 1000ms;
    property<int> count: 0;
    
    callback timeout();
    
    animate count {
        duration: interval;
        iteration-count: -1;  // бесконечно
        easing: linear;
        
        // Вызывается при каждой итерации анимации
        running: root.running;
        
        // Вызывается при каждом обновлении свойства
        update: {
            if (running) {
                timeout();
            }
        }
    }
}

Пример использования таймера

Timer {
    running: true;
    interval: 500ms;
    
    timeout => {
        counter += 1;
        debug("Таймер сработал: " + counter);
    }
}

Кастомные рендеры

Использование Path для сложных фигур

Path {
    commands: "M 0 0 L 100 0 L 50 100 Z";  // треугольник
    fill: blue;
    stroke: red;
    stroke-width: 2px;
}

Path {
    // Звезда
    commands: "M 50 0 L 61 35 L 98 35 L 68 57 L 79 91 L 50 70 L 21 91 L 32 57 L 2 35 L 39 35 Z";
    fill: gold;
    stroke: black;
    stroke-width: 1px;
}

Использование Canvas

export component CustomDrawing {
    width: 200px;
    height: 200px;
    
    callback paint-callback(/* canvas context */);
    
    Canvas {
        width: parent.width;
        height: parent.height;
        
        paint => {
            // Рисование на канвасе
            paint-callback();
        }
    }
}

Асинхронные операции

Обработка асинхронных событий

export component AsyncOperation {
    property<bool> loading: false;
    
    callback start-operation();
    callback operation-completed(string);
    
    Button {
        text: "Начать операцию";
        clicked => {
            root.loading = true;
            root.start-operation();
        }
    }
    
    // Вызывается из бэкенда при завершении операции
    public function complete(result: string) {
        root.loading = false;
        root.operation-completed(result);
    }
}

Индикатор загрузки

export component LoadingIndicator {
    property<bool> active: false;
    
    Rectangle {
        visible: active;
        
        animate rotation {
            duration: 1s;
            iteration-count: -1;
            easing: linear;
        }
        
        Image {
            source: @image-url("spinner.png");
            rotation-angle: rotation * 360deg;
        }
    }
}

Доступ к системным ресурсам

Доступ к файловой системе (через бэкенд)

export component FileViewer {
    callback open-file(string);
    callback save-file(string, string);
    
    Button {
        text: "Открыть файл";
        clicked => { root.open-file("*.txt"); }
    }
    
    Button {
        text: "Сохранить файл";
        clicked => { root.save-file("document.txt", text-content); }
    }
    
    property<string> text-content: "";
}

Доступ к системным настройкам

Text {
    color: ColorScheme.is-dark-color-scheme ? white : black;
    text: "Текущая тема: " + (ColorScheme.is-dark-color-scheme ? "Тёмная" : "Светлая");
}

Доступ к системному времени

Text {
    property<int> current-time: 0;
    
    text: "Текущее время: " + Format.time(current-time, "HH:mm:ss");
    
    animate current-time {
        duration: 1s;
        iteration-count: -1;
        easing: linear;
    }
}

Глобальные объекты

Доступ к глобальным объектам

Text {
    text: "Ширина экрана: " + Math.round(Screen.width) + "px";
}

Rectangle {
    x: Math.min(100, 200);
    color: Colors.darker(Colors.blue, 0.2);
}

Математические функции

Rectangle {
    width: Math.max(100px, parent.width / 2);
    height: Math.sqrt(200px * 200px);
    rotation-angle: Math.sin(time) * 30deg;
}

Цветовые функции

Rectangle {
    color: Colors.mix(Colors.red, Colors.blue, 0.5);  // фиолетовый
}

Rectangle {
    color: Colors.brighter(Colors.blue, 0.2);  // более светлый синий
}

Rectangle {
    color: Colors.darker(Colors.green, 0.3);  // более темный зеленый
}

Rectangle {
    color: Colors.transparentize(Colors.red, 0.5);  // полупрозрачный красный
}

Оптимизация производительности

Кэширование элементов

component CachedItem {
    cache-rendering: true;  // кэшировать рендеринг
    
    // сложный элемент с множеством дочерних элементов
    VerticalLayout {
        for i in 100: Rectangle {
            height: 10px;
            color: Colors.mix(blue, red, i / 100);
        }
    }
}

Условная отрисовка

if is-visible: Rectangle {
    // отрисовывается только если is-visible == true
}

Rectangle {
    visible: is-visible;  // альтернативный способ
}

Ленивая загрузка

if active-tab == "settings": SettingsPage { }
else if active-tab == "profile": ProfilePage { }
else: HomePage { }

Стилизация

Градиенты

// Линейный градиент
Rectangle {
    background: @linear-gradient(90deg, red, blue);
}

// Радиальный градиент
Rectangle {
    background: @radial-gradient(circle, red, blue);
}

// Градиент с несколькими точками остановки
Rectangle {
    background: @linear-gradient(90deg, red 0%, yellow 50%, blue 100%);
}

Тени

Rectangle {
    drop-shadow: 2px 2px 5px #00000080;
    drop-shadow-color: #00000080;
    drop-shadow-offset-x: 2px;
    drop-shadow-offset-y: 2px;
    drop-shadow-blur: 5px;
}

Изображения

Rectangle {
    background: @image-url("path/to/image.png");
    background-size: cover;  // contain, cover, fill
}

Шрифты

Text {
    font-family: "Roboto";
    font-weight: bold;  // normal, bold
    font-style: italic;  // normal, italic
    font-size: 16px;
    letter-spacing: 1px;
    text-decoration: underline;  // none, underline, line-through
}

Отладка и инспектирование

Отладочные границы

Rectangle {
    debug: true;  // показывает границы элемента в режиме отладки
}

Отладочная информация

debug(variable);  // вывод в консоль
debug("Значение: " + variable);

Инспектирование свойств

export component DebugInfo {
    property<string> debug-text;
    
    function update-debug-info() {
        debug-text = "Размер: " + width + "x" + height + 
                      ", Позиция: " + x + "," + y;
    }
    
    // Вызов при каждом изменении размера
    width => { update-debug-info(); }
    height => { update-debug-info(); }
    x => { update-debug-info(); }
    y => { update-debug-info(); }
}

Взаимодействие с бэкендом

Экспорт функций для бэкенда

export component App {
    callback request-data();
    
    function update-data(new-data: string) {
        data = new-data;
    }
    
    property<string> data;
}

Вызов функций из бэкенда

export component Counter {
    property<int> value: 0;
    
    public function increment() {
        value += 1;
    }
    
    public function decrement() {
        value -= 1;
    }
    
    public function reset() {
        value = 0;
    }
    
    public function set-value(new-value: int) {
        value = new-value;
    }
}

Передача данных в бэкенд

export component Form {
    property<string> username: "";
    property<string> password: "";
    
    callback submit-form(string, string);
    
    Button {
        text: "Отправить";
        clicked => {
            root.submit-form(root.username, root.password);
        }
    }
}

Обработка асинхронных ответов

export component ApiClient {
    property<bool> loading: false;
    property<string> result: "";
    property<string> error: "";
    
    callback send-request(string);
    
    public function handle-response(response: string) {
        loading = false;
        result = response;
        error = "";
    }
    
    public function handle-error(error-message: string) {
        loading = false;
        result = "";
        error = error-message;
    }
    
    Button {
        text: "Отправить запрос";
        clicked => {
            loading = true;
            result = "";
            error = "";
            send-request("https://api.example.com/data");
        }
    }
}

Работа с изображениями

Загрузка изображений

Image {
    source: @image-url("path/to/image.png");
    width: 200px;
    height: 150px;
}

Масштабирование изображений

Image {
    source: @image-url("path/to/image.png");
    image-fit: contain;  // contain, cover, fill
    image-rendering: smooth;  // smooth, pixelated
}

Обрезка изображений

Image {
    source: @image-url("path/to/image.png");
    source-clip-x: 50px;
    source-clip-y: 50px;
    source-clip-width: 100px;
    source-clip-height: 100px;
}

Тонирование изображений

Image {
    source: @image-url("path/to/icon.png");
    colorize: Theme.primary-color;  // применяет цвет к изображению
}

Работа с текстом

Форматирование текста

Text {
    text: "Обычный текст";
    font-size: 16px;
    font-weight: bold;  // normal, bold
    font-style: italic;  // normal, italic
    text-decoration: underline;  // none, underline, line-through
}

Многострочный текст

Text {
    text: "Это длинный текст, который будет перенесен на несколько строк при необходимости.";
    wrap: word-wrap;  // no-wrap, word-wrap
    height: 100px;
    width: 200px;
}

Обрезка текста

Text {
    text: "Очень длинный текст, который будет обрезан";
    overflow: elide;  // clip, elide
    max-width: 100px;
    elide-mode: middle;  // start, middle, end
}

Выравнивание текста

Text {
    text: "Выровненный текст";
    horizontal-alignment: center;  // left, center, right
    vertical-alignment: center;  // top, center, bottom
}

Работа с цветами

Определение цветов

// Шестнадцатеричная запись
property<color> red: #ff0000;
property<color> green: #00ff00;
property<color> blue: #0000ff;

// Запись с прозрачностью
property<color> semi-transparent-red: #ff000080;

// Функциональная запись
property<color> yellow: rgb(255, 255, 0);
property<color> cyan: rgba(0, 255, 255, 0.5);

Манипуляции с цветами

// Смешивание цветов
property<color> purple: Colors.mix(red, blue, 0.5);

// Изменение яркости
property<color> light-blue: Colors.brighter(blue, 0.2);
property<color> dark-blue: Colors.darker(blue, 0.2);

// Изменение прозрачности
property<color> transparent-green: Colors.transparentize(green, 0.5);

Градиенты

// Линейный градиент
background: @linear-gradient(90deg, red, blue);
background: @linear-gradient(45deg, red 0%, yellow 50%, blue 100%);

// Радиальный градиент
background: @radial-gradient(circle, red, blue);
background: @radial-gradient(circle at top left, red 0%, blue 100%);

Трансформации

Позиционирование

Rectangle {
    x: 10px;
    y: 20px;
    width: 100px;
    height: 50px;
}

Масштабирование

Rectangle {
    scale: 1.5;  // увеличение в 1.5 раза
    scale-x: 2.0;  // растяжение по горизонтали
    scale-y: 0.5;  // сжатие по вертикали
}

Вращение

Rectangle {
    rotation-angle: 45deg;
    rotation-origin-x: 50%;
    rotation-origin-y: 50%;
}

Наклон (Skew)

Rectangle {
    transform: skew(30deg, 0deg);
}

Комбинированные трансформации

Rectangle {
    transform: rotate(45deg) translate(10px, 20px) scale(1.5);
}

Работа с сеткой и выравниванием

Выравнивание в сетке

GridLayout {
    Row {
        Rectangle { colspan: 2; rowspan: 1; }
        Rectangle { colspan: 1; rowspan: 2; }
    }
    Row {
        Rectangle { horizontal-stretch: 1; }
        Rectangle { horizontal-stretch: 2; }  // займет в 2 раза больше места
    }
}

Выравнивание в контейнерах

VerticalLayout {
    alignment: start;  // start, center, end, space-between, space-around
    spacing: 10px;
    
    Rectangle { height: 50px; }
    Rectangle { height: 50px; }
}

HorizontalLayout {
    alignment: space-between;
    spacing: 10px;
    
    Rectangle { width: 50px; }
    Rectangle { width: 50px; }
}

Отступы

VerticalLayout {
    padding: 10px;
    padding-left: 20px;
    padding-right: 20px;
    padding-top: 5px;
    padding-bottom: 5px;
    
    Rectangle { }
    Rectangle { }
}

Работа с размерами

Единицы измерения

// Пиксели
width: 100px;
height: 50px;

// Проценты
width: 50%;
height: 25%;

// Физические единицы
width: 2cm;
height: 1in;

// Относительные единицы
width: parent.width / 2;
height: parent.height * 0.75;

Минимальные и максимальные размеры

Rectangle {
    width: 100px;
    min-width: 50px;
    max-width: 200px;
    
    height: 100px;
    min-height: 50px;
    max-height: 200px;
}

Соотношение сторон

Rectangle {
    width: 100px;
    height: self.width * 9/16;  // соотношение 16:9
}

Работа с пользовательским вводом

Обработка клавиатурного ввода

FocusScope {
    key-pressed(event) => {
        if (event.text == "Enter") {
            submit-form();
            return accept;
        } else if (event.text == "Escape") {
            cancel-form();
            return accept;
        }
        return reject;
    }
}

Обработка мыши и касаний

TouchArea {
    clicked => {
        debug("Клик по координатам: " + self.mouse-x + ", " + self.mouse-y);
    }
    
    moved => {
        debug("Перемещение указателя: " + self.mouse-x + ", " + self.mouse-y);
    }
    
    pointer-event(event) => {
        if (event.kind == pressed) {
            debug("Нажатие кнопки: " + event.button);
        }
        return accept;
    }
}

Перетаскивание

Rectangle {
    property<bool> dragging: false;
    property<length> start-x: 0px;
    property<length> start-y: 0px;
    
    TouchArea {
        pressed => {
            root.dragging = true;
            root.start-x = root.x - self.mouse-x;
            root.start-y = root.y - self.mouse-y;
        }
        
        moved => {
            if (root.dragging) {
                root.x = root.start-x + self.mouse-x;
                root.y = root.start-y + self.mouse-y;
            }
        }
        
        released => {
            root.dragging = false;
        }
    }
}

Колесо мыши

TouchArea {
    wheel-event(event) => {
        scroll-position += event.delta-y;
        return accept;
    }
}

Работа с анимациями

Базовая анимация

Rectangle {
    color: blue;
    
    animate color { duration: 250ms; easing: ease-in-out; }
}

Анимация с задержкой

Rectangle {
    color: blue;
    
    animate color { duration: 500ms; delay: 200ms; easing: ease; }
}

Повторяющаяся анимация

Rectangle {
    property<float> rotation: 0;
    
    animate rotation {
        duration: 2s;
        iteration-count: infinite;  // -1 или infinite для бесконечного повторения
        easing: linear;
    }
    
    rotation-angle: rotation * 360deg;
}

Анимация с ключевыми кадрами

Rectangle {
    property<float> progress: 0;
    
    animate progress {
        duration: 3s;
        iteration-count: infinite;
        easing: linear;
        
        keyframes: [
            { target: 0; duration: 0ms; },
            { target: 0.25; duration: 1s; easing: ease-in; },
            { target: 0.75; duration: 1s; easing: ease-out; },
            { target: 1; duration: 1s; easing: ease-in-out; }
        ];
    }
    
    x: progress * (parent.width - self.width);
    color: progress < 0.5 ? blue : red;
}

Переходы между состояниями

Rectangle {
    color: blue;
    
    states [
        active when is-active: {
            color: red;
        }
    ]
    
    // Анимация при переходе между состояниями
    transitions [
        transition active to !active: {
            animate color { duration: 250ms; easing: ease-out; }
        }
        transition !active to active: {
            animate color { duration: 500ms; easing: ease-in; }
        }
    ]
}

Работа со сложными структурами данных

Определение структур

struct Person {
    name: string,
    age: int,
    address: Address,
}

struct Address {
    street: string,
    city: string,
    zip: string,
}

Использование структур

export component PersonView {
    property<Person> person: {
        name: "Иван Иванов",
        age: 30,
        address: {
            street: "Ленина 1",
            city: "Москва",
            zip: "123456"
        }
    };
    
    VerticalLayout {
        Text { text: "Имя: " + person.name; }
        Text { text: "Возраст: " + person.age; }
        Text { text: "Адрес: " + person.address.street + ", " + 
                     person.address.city + ", " + person.address.zip; }
    }
}

Работа с массивами

export component PeopleList {
    property<[Person]> people: [
        {
            name: "Иван",
            age: 30,
            address: { street: "Ленина 1", city: "Москва", zip: "123456" }
        },
        {
            name: "Мария",
            age: 25,
            address: { street: "Пушкина 2", city: "Санкт-Петербург", zip: "654321" }
        }
    ];
    
    VerticalLayout {
        for person[i] in people: Rectangle {
            VerticalLayout {
                Text { text: person.name; }
                Text { text: "Возраст: " + person.age; }
            }
            
            TouchArea {
                clicked => {
                    selected-index = i;
                }
            }
            
            background: i == selected-index ? #e0e0e0 : transparent;
        }
    }
    
    property<int> selected-index: -1;
}

Модификация данных

export component PersonEditor {
    property<Person> person;
    
    callback person-changed(Person);
    
    function update-name(new-name: string) {
        // Создаем новый объект с обновленным полем
        var updated-person = person;
        updated-person.name = new-name;
        person = updated-person;
        person-changed(person);
    }
    
    VerticalLayout {
        TextInput {
            text: person.name;
            edited => {
                update-name(self.text);
            }
        }
        
        // Другие поля редактирования...
    }
}

Советы и рекомендации

Организация кода

// Разделение на компоненты
component Header {
    // ...
}

component Sidebar {
    // ...
}

component Content {
    // ...
}

export component MainWindow {
    VerticalLayout {
        Header { }
        
        HorizontalLayout {
            Sidebar { width: 200px; }
            Content { }
        }
    }
}

Повторное использование стилей

component StyledButton {
    property<string> text;
    property<brush> background: Theme.button-background;
    property<color> text-color: Theme.button-text;
    
    callback clicked();
    
    Rectangle {
        background: root.background;
        border-radius: Theme.border-radius;
        
        Text {
            text: root.text;
            color: root.text-color;
        }
        
        TouchArea {
            clicked => { root.clicked(); }
        }
    }
}

// Использование
StyledButton {
    text: "Обычная кнопка";
    clicked => { /* ... */ }
}

StyledButton {
    text: "Важная кнопка";
    background: Theme.primary-color;
    text-color: white;
    clicked => { /* ... */ }
}

Отзывчивый дизайн

export component ResponsiveLayout {
    property<length> breakpoint: 600px;
    
    if parent.width > breakpoint: HorizontalLayout {
        Rectangle { background: blue; width: 30%; }
        Rectangle { background: green; width: 70%; }
    } else: VerticalLayout {
        Rectangle { background: blue; height: 30%; }
        Rectangle { background: green; height: 70%; }
    }
}

Оптимизация производительности

  1. Используйте cache-rendering: true для сложных компонентов, которые редко меняются
  2. Избегайте сложных вычислений в привязках свойств
  3. Используйте visible: false вместо условного рендеринга для временно скрытых элементов
  4. Ограничивайте количество анимаций, выполняемых одновременно
// Пример оптимизации
component ComplexItem {
    cache-rendering: true;
    
    // Сложное содержимое
    for i in 100: Rectangle {
        y: i * 2px;
        height: 1px;
        color: Colors.mix(blue, red, i / 100);
    }
}

Отладка

// Отладка значений
debug("Значение: " + value);

// Отладка размеров
Rectangle {
    debug: true;  // показывает границы и размеры
}

// Отладка состояний
if debug-mode: Text {
    text: "Текущее состояние: " + current-state;
    color: red;
}

Заключение

Эта шпаргалка охватывает большинство возможностей языка разметки Slint, от базовых элементов до продвинутых техник. Используйте ее как справочник при разработке пользовательских интерфейсов на Slint.

Помните, что Slint постоянно развивается, поэтому рекомендуется также обращаться к официальной документации для получения самой актуальной информации: https://slint.dev/docs/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment