# X11 GUI Library [![Platform](https://img.shields.io/badge/platform-Linux-blue)]() [![C++](https://img.shields.io/badge/C++-20-blue)]() [![License](https://img.shields.io/badge/license-MIT-green)]() Лёгкая 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 | |:---:|:---:| | ![win11](docs/screenshots/theme_win11.png) | ![terminal](docs/screenshots/theme_terminal.png) | Переключение на лету — клавиша **F6**. ### Виджеты | Controls (кнопки, ввод, чекбоксы, слайдер, прогресс) | Lists (список, dropdown, дерево, скролл) | |:---:|:---:| | ![controls](docs/screenshots/widgets_controls.png) | ![lists](docs/screenshots/widgets_lists.png) | | Graphics (RawPicture: круги, полигоны, текст) | |:---:| | ![graphics](docs/screenshots/widgets_graphics.png) | ### Отладка | Debug overlay (F1) — FPS, виджеты, partial updates, лог событий | |:---:| | ![overlay](docs/screenshots/debug_overlay.png) | --- ## 🚀 Быстрый старт ```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 items;// listbox / dropdown std::shared_ptr 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)