281 lines
11 KiB
Markdown
281 lines
11 KiB
Markdown
# X11 GUI Library
|
||
|
||
[]()
|
||
[]()
|
||
[]()
|
||
|
||
Лёгкая GUI-библиотека для C++20 на X11: программный рендеринг, частичная перерисовка (dirty rectangles), TTF-шрифты (FreeType), две темы (WIN11 / TERMINAL), плавные анимации и встроенная отладка как в Android Studio.
|
||
|
||
---
|
||
|
||
## ✨ Возможности
|
||
|
||
- **Частичная перерисовка** — обновляются только изменённые области, а не весь экран
|
||
- **Двойная буферизация** — без мерцания
|
||
- **TTF/TTC шрифты** через FreeType с кешированием (быстрый текст)
|
||
- **Две темы**: `WIN11` (скругления, синий акцент) и `TERMINAL` (квадратная, зелёная) + полная кастомизация
|
||
- **Анимации**: hover, нажатие (push-down), галочки, dropdown, мигающий курсор
|
||
- **EventBus** + колбэки на виджетах
|
||
- **Отладка**: оверлей FPS, визуализация dirty-областей, маркеры кликов, границы виджетов (F1–F6)
|
||
- **Только активная страница** рендерится — остальные не жгут CPU
|
||
|
||
---
|
||
|
||
## 🖼 Скриншоты
|
||
|
||
### Темы
|
||
|
||
| WIN11 | TERMINAL |
|
||
|:---:|:---:|
|
||
|  |  |
|
||
|
||
Переключение на лету — клавиша **F6**.
|
||
|
||
### Виджеты
|
||
|
||
| Controls (кнопки, ввод, чекбоксы, слайдер, прогресс) | Lists (список, dropdown, дерево, скролл) |
|
||
|:---:|:---:|
|
||
|  |  |
|
||
|
||
| Graphics (RawPicture: круги, полигоны, текст) |
|
||
|:---:|
|
||
|  |
|
||
|
||
### Отладка
|
||
|
||
| Debug overlay (F1) — FPS, виджеты, partial updates, лог событий |
|
||
|:---:|
|
||
|  |
|
||
|
||
---
|
||
|
||
## 🚀 Быстрый старт
|
||
|
||
```cpp
|
||
#include "gui.h"
|
||
|
||
int main() {
|
||
gui::set_theme(gui::ThemeStyle::WIN11);
|
||
gui::window win("My App");
|
||
win.set_font("SGr-Iosevka-Regular.ttc"); // любой TTF/TTC рядом с бинарником
|
||
win.set_default_icon();
|
||
|
||
win.configur_page("main", [](gui::page& p) {
|
||
gui::WidgetData b;
|
||
b.id = "btn"; b.text = "Hello";
|
||
b.x = 100; b.y = 100; b.width = 300; b.height = 70;
|
||
b.primary = true; // акцентная кнопка
|
||
p.Button(b);
|
||
}, true);
|
||
|
||
gui::EventBus::get().on("button.click", [](const gui::EventData& e) {
|
||
std::cout << "clicked: " << e.source_id << "\n";
|
||
});
|
||
|
||
while (win.running()) win.update();
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
Или просто запусти демо со всеми виджетами:
|
||
|
||
```cpp
|
||
#include "gui.h"
|
||
int main() { gui::run_demo(); }
|
||
```
|
||
|
||
---
|
||
|
||
## 🛠 Сборка
|
||
|
||
### Зависимости
|
||
|
||
```bash
|
||
# Ubuntu/Debian
|
||
sudo apt install libx11-dev libfreetype-dev cmake g++
|
||
|
||
# Fedora
|
||
sudo dnf install libX11-devel freetype-devel cmake gcc-c++
|
||
|
||
# Arch
|
||
sudo pacman -S libx11 freetype2 cmake
|
||
```
|
||
|
||
### CMake
|
||
|
||
```cmake
|
||
cmake_minimum_required(VERSION 3.10)
|
||
project(host)
|
||
set(CMAKE_CXX_STANDARD 20)
|
||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||
|
||
find_package(X11 REQUIRED)
|
||
find_package(Freetype REQUIRED)
|
||
|
||
add_executable(host
|
||
main.cpp
|
||
libs/gui/core/event_bus.cpp
|
||
libs/gui/core/raw_picture.cpp
|
||
libs/gui/core/font_manager.cpp
|
||
libs/gui/core/theme.cpp
|
||
libs/gui/widgets/widget.cpp
|
||
libs/gui/widgets/draw_basic.cpp
|
||
libs/gui/widgets/draw_toggles.cpp
|
||
libs/gui/widgets/draw_lists.cpp
|
||
libs/gui/window.cpp
|
||
libs/gui/demo.cpp
|
||
)
|
||
target_include_directories(host PRIVATE libs/gui ${X11_INCLUDE_DIR})
|
||
target_link_libraries(host PRIVATE ${X11_LIBRARIES} Freetype::Freetype)
|
||
```
|
||
|
||
```bash
|
||
mkdir build && cd build
|
||
cmake ..
|
||
make -j$(nproc)
|
||
./host
|
||
```
|
||
|
||
> Положи `SGr-Iosevka-Regular.ttc` (или любой TTF) рядом с бинарником. Если шрифт не найден — используется фолбэк на X11 core font.
|
||
|
||
---
|
||
|
||
## 🧩 Виджеты
|
||
|
||
| Метод | Тип | Описание |
|
||
|-------|-----|----------|
|
||
| `Button(d)` | BUTTON | Кнопка (`primary = true` — акцентная) |
|
||
| `Label(d)` | LABEL | Текстовая метка |
|
||
| `Input(d)` | INPUT | Поле ввода: клик — фокус, нижняя линия, мигающий курсор, Enter — `input.submit` |
|
||
| `Checkbox(d)` | CHECKBOX | Флажок с анимированной галочкой |
|
||
| `Radiobutton(d)` | RADIO | Радио-кнопка (группа по `id`) |
|
||
| `Slider(d)` | SLIDER | Ползунок 0..1, перетаскивание |
|
||
| `Progressbar(d)` | PROGRESS | Прогресс (+ `indeterminate` — бегущий) |
|
||
| `Listbox(d)` | LISTBOX | Список с прокруткой и выделением |
|
||
| `Dropdown(d)` | DROPDOWN | Выпадающий список с анимацией |
|
||
| `TreeView(d)` + `TreeNode(d)` | TREE_VIEW / TREE | Дерево с раскрытием `[+]/[-]` |
|
||
| `ScrollView(d)` | SCROLL | Контейнер с прокруткой |
|
||
| `RawPictureWidget(d)` | RAW_PIC | Картинка из `RawPicture` |
|
||
| `SpriteButton(d)` | SPRITE_BTN | Кликабельный спрайт |
|
||
|
||
### Основные поля `WidgetData`
|
||
|
||
```cpp
|
||
std::string id, text; // идентификатор и подпись
|
||
int x, y, width, height; // геометрия (масштаб x2)
|
||
unsigned long bg_color, fg_color, frame_color; // 0 = из темы, иначе override
|
||
int font_size; // 0 = системный, иначе свой
|
||
bool primary; // акцентная кнопка
|
||
bool checked; // checkbox / radio
|
||
float value, target_value; // slider / progress (0..1)
|
||
std::vector<std::string> items;// listbox / dropdown
|
||
std::shared_ptr<RawPicture> picture;
|
||
// колбэки:
|
||
on_change / on_page_click / on_window_click
|
||
```
|
||
|
||
---
|
||
|
||
## 🐞 Отладка
|
||
|
||
### Горячие клавиши
|
||
|
||
| Клавиша | Действие |
|
||
|---------|----------|
|
||
| **F1** | Debug overlay: FPS, кол-во виджетов, счётчик partial updates, координаты мыши, лог последних событий |
|
||
| **F2** | Визуализация dirty rectangles — мигание перерисованных областей (как «Show screen updates» в Android) |
|
||
| **F3** | Маркеры кликов — красный крестик в точке нажатия |
|
||
| **F4** | Границы всех виджетов (magenta) |
|
||
| **F5** | Логирование событий в консоль |
|
||
| **F6** | Переключение темы WIN11 ↔ TERMINAL |
|
||
|
||
### Как читать оверлей (F1)
|
||
|
||
- **FPS** — реальная частота перерисовок (в простое ~0, при анимациях до `max_fps`)
|
||
- **Widgets** — виджетов на активной странице
|
||
- **Partial updates** — сколько dirty-областей перерисовано всего. Растёт медленно = оптимизация работает
|
||
- **Mouse** — координаты курсора
|
||
- **EVENT LOG** — последние 5 событий шины
|
||
|
||
### Что показывает F2
|
||
|
||
Каждая перерисованная область на 0.2 сек подсвечивается XOR-цветом. Наведи на кнопку — мигнёт только она. Двинь слайдер — мигнёт только слайдер. Если мигает весь экран — значит ты сам позвал `mark_all_dirty()`.
|
||
|
||
### Программное управление
|
||
|
||
```cpp
|
||
win.debug().show_debug_overlay = true; // F1
|
||
win.debug().show_dirty_rects = true; // F2
|
||
win.debug().show_click_markers = true; // F3
|
||
win.debug().show_widget_bounds = true; // F4
|
||
win.debug().log_to_console = true; // F5
|
||
win.debug().max_log_size = 30;
|
||
|
||
win.mark_dirty(x, y, w, h); // пометить область как грязную
|
||
win.mark_all_dirty(); // перерисовать всё
|
||
win.set_max_fps(144); // лимит кадров
|
||
```
|
||
|
||
---
|
||
|
||
3. Что снять (имена файлов = ссылки в README):
|
||
|
||
| Файл | Что показать |
|
||
|------|--------------|
|
||
| `theme_win11.png` | демо в теме WIN11 |
|
||
| `theme_terminal.png` | нажми F6 → тема TERMINAL |
|
||
| `widgets_controls.png` | страница controls |
|
||
| `widgets_lists.png` | страница lists |
|
||
| `widgets_graphics.png` | страница graphics |
|
||
| `debug_overlay.png` | нажми F1 |
|
||
| `debug_dirty.png` | F2 + покликай кнопки |
|
||
| `debug_clicks.png` | F3 + покликай |
|
||
| `debug_bounds.png` | F4 |
|
||
|
||
4. Закоммить папку `docs/screenshots/` — и картинки появятся на Gitea.
|
||
|
||
---
|
||
|
||
## 📁 Структура проекта
|
||
|
||
```
|
||
/
|
||
├── README.md
|
||
├── docs/
|
||
│ ├── index.html ← интерактивная документация
|
||
│ └── screenshots/ ← скриншоты для README
|
||
└── gui/
|
||
├── gui.h ← umbrella-заголовок
|
||
├── demo.h / demo.cpp ← run_demo()
|
||
├── window.h / window.cpp ← окно, dirty-рендер, оверлей, иконка
|
||
├── core/
|
||
│ ├── common.h ← EventData, DebugInfo, DirtyRegion, easing
|
||
│ ├── event_bus.h/.cpp
|
||
│ ├── raw_picture.h/.cpp ← пиксельный буфер + примитивы + BMP/PPM
|
||
│ ├── font_manager.h/.cpp ← TTF + кеш текста
|
||
│ └── theme.h/.cpp ← WIN11 / TERMINAL
|
||
└── widgets/
|
||
├── widget.h / widget.cpp ← WidgetData, Widget, combat, page
|
||
├── draw_basic.cpp ← Button, Label, Input, Sprite
|
||
├── draw_toggles.cpp ← Checkbox, Radio, Slider, Progress
|
||
└── draw_lists.cpp ← Listbox, Dropdown, Tree, Scroll
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 Документация
|
||
|
||
Полная интерактивная документация (9 страниц: старт, окно, виджеты, темы, свои виджеты, события, анимации, отладка, API):
|
||
|
||
👉 **[docs/index.html](docs/index.html)** — открой в браузере
|
||
|
||
---
|
||
|
||
## 📄 Лицензия
|
||
|
||
MIT.
|
||
|
||
## 👤 Автор
|
||
|
||
**KoDer** — [git.bipfr.ru/KoDer/gui](https://git.bipfr.ru/KoDer)
|