Обновить docs.html

This commit is contained in:
KoDer 2026-08-24 11:10:00 +00:00
parent eb4ed1339c
commit 58894fbf4e

533
docs.html
View File

@ -1,10 +1,15 @@
---
## 📄 `docs/index.html` (обновлённая HTML-документация)
```html
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ru"> <html lang="ru">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GUI Library Documentation</title> <title>X11 GUI Library - Documentation</title>
<!-- Подключаем шрифты и иконки -->
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
<style> <style>
@ -17,6 +22,8 @@
--accent: #38bdf8; --accent: #38bdf8;
--accent-hover: #0ea5e9; --accent-hover: #0ea5e9;
--success: #22c55e; --success: #22c55e;
--warning: #f59e0b;
--danger: #ef4444;
--border: #334155; --border: #334155;
--code-bg: #0d1117; --code-bg: #0d1117;
} }
@ -32,13 +39,11 @@
min-height: 100vh; min-height: 100vh;
} }
/* Скроллбар */
::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: var(--bg-primary); } ::-webkit-scrollbar-track { background: var(--bg-primary); }
::-webkit-scrollbar-thumb { background: var(--bg-tertiary); border-radius: 4px; } ::-webkit-scrollbar-thumb { background: var(--bg-tertiary); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: var(--accent); } ::-webkit-scrollbar-thumb:hover { background: var(--accent); }
/* Боковая панель */
.sidebar { .sidebar {
width: 280px; width: 280px;
background-color: var(--bg-secondary); background-color: var(--bg-secondary);
@ -98,7 +103,6 @@
color: var(--accent); color: var(--accent);
} }
/* Основной контент */
.main-content { .main-content {
margin-left: 280px; margin-left: 280px;
flex: 1; flex: 1;
@ -121,8 +125,9 @@
font-family: 'JetBrains Mono', monospace; font-family: 'JetBrains Mono', monospace;
margin-right: 0.5rem; margin-right: 0.5rem;
} }
.badge.new { background: var(--success); color: white; }
.badge.warning { background: var(--warning); color: black; }
/* Блоки кода */
.code-wrapper { .code-wrapper {
position: relative; position: relative;
margin: 1.5rem 0; margin: 1.5rem 0;
@ -156,7 +161,6 @@
pre { margin: 0 !important; border-radius: 0 !important; background: var(--code-bg) !important; } pre { margin: 0 !important; border-radius: 0 !important; background: var(--code-bg) !important; }
code { font-family: 'JetBrains Mono', monospace !important; font-size: 0.9rem !important; } code { font-family: 'JetBrains Mono', monospace !important; font-size: 0.9rem !important; }
/* Таблицы */
table { table {
width: 100%; width: 100%;
border-collapse: collapse; border-collapse: collapse;
@ -174,7 +178,6 @@
td { color: var(--text-secondary); } td { color: var(--text-secondary); }
td code { background: var(--bg-primary); padding: 0.2rem 0.4rem; border-radius: 4px; color: var(--accent); } td code { background: var(--bg-primary); padding: 0.2rem 0.4rem; border-radius: 4px; color: var(--accent); }
/* Аккордеон для API */
details { details {
background: var(--bg-secondary); background: var(--bg-secondary);
border: 1px solid var(--border); border: 1px solid var(--border);
@ -200,6 +203,55 @@
.highlight { color: var(--accent); font-weight: 600; } .highlight { color: var(--accent); font-weight: 600; }
.feature-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.feature-card {
background: var(--bg-secondary);
padding: 1.5rem;
border-radius: 8px;
border: 1px solid var(--border);
transition: all 0.2s;
}
.feature-card:hover {
border-color: var(--accent);
transform: translateY(-2px);
}
.feature-card .icon {
font-size: 2rem;
margin-bottom: 0.5rem;
}
.feature-card h4 { color: var(--text-primary); margin-bottom: 0.5rem; }
.hotkey-grid {
display: grid;
grid-template-columns: 80px 1fr;
gap: 0.5rem;
margin: 1rem 0;
}
.hotkey-key {
background: var(--bg-tertiary);
color: var(--accent);
padding: 0.5rem 1rem;
border-radius: 6px;
font-family: 'JetBrains Mono', monospace;
text-align: center;
font-weight: 600;
}
.alert {
padding: 1rem;
border-radius: 8px;
margin: 1.5rem 0;
border-left: 4px solid;
}
.alert.success { background: rgba(34, 197, 94, 0.1); border-color: var(--success); }
.alert.warning { background: rgba(245, 158, 11, 0.1); border-color: var(--warning); }
.alert.info { background: rgba(56, 189, 248, 0.1); border-color: var(--accent); }
@media (max-width: 768px) { @media (max-width: 768px) {
.sidebar { transform: translateX(-100%); transition: transform 0.3s; } .sidebar { transform: translateX(-100%); transition: transform 0.3s; }
.sidebar.open { transform: translateX(0); } .sidebar.open { transform: translateX(0); }
@ -209,19 +261,18 @@
</head> </head>
<body> <body>
<!-- Боковая навигация -->
<nav class="sidebar"> <nav class="sidebar">
<div class="logo"> <div class="logo">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18M9 21V9"/></svg>
X11 GUI Lib X11 GUI Lib
</div> </div>
<input type="text" class="search-box" placeholder="Поиск по документации..." id="searchInput"> <input type="text" class="search-box" placeholder="Поиск..." id="searchInput">
<div class="nav-group"> <div class="nav-group">
<div class="nav-title">Начало работы</div> <div class="nav-title">Начало</div>
<a href="#intro" class="nav-link">Введение</a> <a href="#intro" class="nav-link">Введение</a>
<a href="#features" class="nav-link">Возможности</a>
<a href="#quickstart" class="nav-link">Быстрый старт</a> <a href="#quickstart" class="nav-link">Быстрый старт</a>
<a href="#architecture" class="nav-link">Архитектура</a>
</div> </div>
<div class="nav-group"> <div class="nav-group">
<div class="nav-title">Компоненты</div> <div class="nav-title">Компоненты</div>
@ -230,7 +281,18 @@
<a href="#widgets" class="nav-link">Виджеты</a> <a href="#widgets" class="nav-link">Виджеты</a>
</div> </div>
<div class="nav-group"> <div class="nav-group">
<div class="nav-title">API Справочник</div> <div class="nav-title">Оптимизация <span class="badge new">NEW</span></div>
<a href="#dirty-rects" class="nav-link">Dirty Rectangles</a>
<a href="#double-buffer" class="nav-link">Двойная буферизация</a>
</div>
<div class="nav-group">
<div class="nav-title">Отладка <span class="badge new">NEW</span></div>
<a href="#debug-hotkeys" class="nav-link">Горячие клавиши</a>
<a href="#debug-overlay" class="nav-link">Debug Overlay</a>
<a href="#debug-programmatic" class="nav-link">API отладки</a>
</div>
<div class="nav-group">
<div class="nav-title">API</div>
<a href="#api-window" class="nav-link">gui::window</a> <a href="#api-window" class="nav-link">gui::window</a>
<a href="#api-page" class="nav-link">gui::page</a> <a href="#api-page" class="nav-link">gui::page</a>
<a href="#api-combat" class="nav-link">gui::combat</a> <a href="#api-combat" class="nav-link">gui::combat</a>
@ -238,16 +300,54 @@
</div> </div>
</nav> </nav>
<!-- Основной контент -->
<main class="main-content"> <main class="main-content">
<section id="intro"> <section id="intro">
<h1>Документация GUI Библиотеки</h1> <h1>📘 X11 GUI Library</h1>
<p>Легковесная, кроссплатформенная (X11) библиотека для создания графических интерфейсов на C++. Поддерживает программный рендеринг, анимации, иерархию виджетов и событийно-ориентированную архитектуру.</p> <p>Современная легковесная GUI библиотека для C++ с поддержкой X11, оптимизированная для производительности через систему частичной перерисовки и предоставляющая профессиональные инструменты отладки уровня Android Studio.</p>
<div class="alert info">
<strong>💡 Версия 2.0</strong> - добавлены: Dirty Rectangles, Android-style отладка, двойная буферизация, маркеры кликов, визуализация границ виджетов.
</div>
</section>
<section id="features">
<h2>✨ Возможности</h2>
<div class="feature-grid">
<div class="feature-card">
<div class="icon">⚡</div>
<h4>Dirty Rectangles</h4>
<p>Перерисовка только изменённых областей. Ускорение в 5-50 раз.</p>
</div>
<div class="feature-card">
<div class="icon">🎨</div>
<h4>Двойная буферизация</h4>
<p>Никакого мерцания благодаря backbuffer через X11 Pixmap.</p>
</div>
<div class="feature-card">
<div class="icon">🔍</div>
<h4>Android Debug</h4>
<p>Визуализация dirty rects, границ виджетов, маркеры кликов.</p>
</div>
<div class="feature-card">
<div class="icon">📡</div>
<h4>EventBus</h4>
<p>Слабое связывание через глобальную шину событий.</p>
</div>
<div class="feature-card">
<div class="icon">🎭</div>
<h4>Анимации</h4>
<p>Плавные dropdown и progress bar с ease-функциями.</p>
</div>
<div class="feature-card">
<div class="icon">📦</div>
<h4>Иерархия</h4>
<p>TreeView, ScrollView, вложенные виджеты.</p>
</div>
</div>
</section> </section>
<section id="quickstart"> <section id="quickstart">
<h2>🚀 Быстрый старт</h2> <h2>🚀 Быстрый старт</h2>
<p>Минимальный пример создания окна с кнопкой и обработкой события.</p>
<div class="code-wrapper"> <div class="code-wrapper">
<div class="code-header"> <div class="code-header">
<span>main.cpp</span> <span>main.cpp</span>
@ -256,207 +356,390 @@
<pre><code class="language-cpp">#include "gui.h" <pre><code class="language-cpp">#include "gui.h"
int main() { int main() {
// 1. Создаем окно gui::window win("My App");
gui::window win("Мое Приложение");
// 2. Добавляем страницу
win.addPAGE("main"); win.addPAGE("main");
// 3. Настраиваем страницу виджетами
win.configur_page("main", [](gui::page& p) { win.configur_page("main", [](gui::page& p) {
// Создаем кнопку gui::WidgetData btn;
gui::WidgetData btnData; btn.id = "start_btn";
btnData.id = "my_button"; btn.text = "Start";
btnData.text = "Нажми меня!"; btn.x = 50; btn.y = 50;
btnData.x = 50; btnData.y = 50; btn.width = 150; btn.height = 40;
btnData.width = 150; btnData.height = 40; btn.bg_color = 0x2563EB;
btnData.bg_color = 0x2563EB; // Синий p.Button(btn);
btnData.fg_color = 0xFFFFFF; // Белый текст }, true);
p.Button(btnData); // Включить все режимы отладки
}, true); // true = сделать активной сразу win.debug().show_debug_overlay = true;
win.debug().show_dirty_rects = true;
win.debug().log_to_console = true;
// 4. Подписываемся на событие
gui::EventBus::get().on("button.click", [](const gui::EventData& e) { gui::EventBus::get().on("button.click", [](const gui::EventData& e) {
if (e.source_id == "my_button") { std::cout << "Clicked: " << e.source_id << "\n";
std::cout << "Кнопка нажата!" << std::endl;
}
}); });
// 5. Главный цикл
while (true) { while (true) {
win.update(); // Обработка событий X11 и отрисовка win.update();
// Добавьте std::this_thread::sleep_for для экономии CPU
} }
return 0; return 0;
}</code></pre> }</code></pre>
</div> </div>
</section> </section>
<section id="architecture"> <section id="dirty-rects">
<h2>🏛 Архитектура</h2> <h2>⚡ Dirty Rectangles <span class="badge new">NEW</span></h2>
<p>Библиотека построена на строгой иерархии:</p> <p>Система частичной перерисовки <code>DirtyRegion</code> отслеживает только изменённые области экрана. Когда виджет меняет состояние, он помечает свою область как "грязную", и библиотека перерисовывает только эти области.</p>
<h3>Как это работает</h3>
<ol style="margin-left: 2rem; color: var(--text-secondary);">
<li>Виджет вызывает <code>mark_dirty()</code> при изменении</li>
<li>Область добавляется в <code>DirtyRegion</code></li>
<li>При <code>window::update()</code> перерисовываются только dirty-области</li>
<li><code>XCopyArea</code> копирует только нужные регионы из backbuffer</li>
</ol>
<div class="alert success">
<strong>📊 Результат:</strong> Для интерфейса с 100 виджетами, где меняется 1 элемент, CPU нагрузка снижается в 50+ раз.
</div>
<h3>Автоматическое отслеживание</h3>
<p>Библиотека автоматически помечает как dirty:</p>
<ul style="margin-left: 2rem; color: var(--text-secondary);">
<li><strong>Dropdown</strong> - во время анимации открытия/закрытия</li>
<li><strong>Progressbar</strong> - при изменении значения или в indeterminate-режиме</li>
<li><strong>Slider</strong> - во время drag</li>
<li><strong>Input</strong> - при вводе текста</li>
<li><strong>Expose events</strong> - при восстановлении окна из-под другого</li>
<li><strong>Resize</strong> - весь экран при изменении размера окна</li>
</ul>
</section>
<section id="double-buffer">
<h2>🎨 Двойная буферизация</h2>
<p>Вся отрисовка происходит в off-screen <code>Pixmap</code> (backbuffer), затем нужные области копируются в окно через <code>XCopyArea</code>. Это полностью убирает мерцание при анимациях.</p>
<div class="code-wrapper">
<div class="code-header"><span>Как работает backbuffer</span></div>
<pre><code class="language-cpp">// 1. Создаём backbuffer при инициализации
backbuffer = XCreatePixmap(dpy, win, width, height, depth);
// 2. Вся отрисовка идёт в backbuffer
XFillRectangle(dpy, backbuffer, gc, ...);
XDrawString(dpy, backbuffer, gc, ...);
// 3. Копируем только dirty-регионы в окно
for (auto& rect : dirty_rects) {
XCopyArea(dpy, backbuffer, window, gc,
rect.x, rect.y, rect.width, rect.height,
rect.x, rect.y);
}</code></pre>
</div>
</section>
<section id="debug-hotkeys">
<h2>⌨️ Горячие клавиши отладки <span class="badge new">NEW</span></h2>
<p>Во время работы приложения используйте F-клавиши для переключения режимов отладки:</p>
<div class="hotkey-grid">
<div class="hotkey-key">F1</div>
<div>Toggle <strong>Debug Overlay</strong> - FPS, координаты мыши, лог событий</div>
<div class="hotkey-key">F2</div>
<div>Toggle <strong>Dirty Rectangles</strong> - мигание изменённых областей (Android-style)</div>
<div class="hotkey-key">F3</div>
<div>Toggle <strong>Click Markers</strong> - красные крестики в местах клика</div>
<div class="hotkey-key">F4</div>
<div>Toggle <strong>Widget Bounds</strong> - розовые границы всех виджетов</div>
<div class="hotkey-key">F5</div>
<div>Toggle <strong>Console Logging</strong> - вывод событий в stdout</div>
</div>
<div class="alert warning">
<strong>💡 Совет:</strong> Включите F2 при разработке - вы сразу увидите, какие области перерисовываются и сможете оптимизировать UI.
</div>
</section>
<section id="debug-overlay">
<h2>📊 Debug Overlay</h2>
<p>При нажатии <kbd>F1</kbd> в правом верхнем углу появляется панель с информацией в реальном времени:</p>
<table> <table>
<thead> <thead>
<tr><th>Уровень</th><th>Класс</th><th>Описание</th></tr> <tr><th>Показатель</th><th>Описание</th></tr>
</thead> </thead>
<tbody> <tbody>
<tr><td><span class="badge">1</span></td><td><code>gui::window</code></td><td>Управляет соединением с X11, главным циклом (`update`) и вкладками.</td></tr> <tr><td><code>FPS</code></td><td>Текущий FPS (обновляется каждые 0.5 сек)</td></tr>
<tr><td><span class="badge">2</span></td><td><code>gui::page</code></td><td>Представляет собой вкладку или экран. Наследуется от <code>combat</code>.</td></tr> <tr><td><code>Widgets</code></td><td>Общее количество виджетов на всех страницах</td></tr>
<tr><td><span class="badge">3</span></td><td><code>gui::combat</code></td><td>Базовый контейнер. Хранит коллекцию виджетов и предоставляет фабричные методы для их создания.</td></tr> <tr><td><code>Partial updates</code></td><td>Счётчик частичных обновлений (показывает эффективность dirty rects)</td></tr>
<tr><td><span class="badge">4</span></td><td><code>gui::Widget</code></td><td>Конкретный элемент интерфейса (кнопка, ввод, слайдер). Также наследуется от <code>combat</code>, позволяя создавать вложенные структуры (например, деревья).</td></tr> <tr><td><code>Mouse</code></td><td>Текущие координаты мыши</td></tr>
<tr><td><code>Event Log</code></td><td>Последние 5 событий с полной информацией</td></tr>
</tbody> </tbody>
</table> </table>
</section> </section>
<section id="debug-programmatic">
<h2>🔧 API отладки</h2>
<div class="code-wrapper">
<div class="code-header"><span>Программное управление</span></div>
<pre><code class="language-cpp">gui::window win("App");
// Прямой доступ к настройкам отладки
win.debug().show_debug_overlay = true;
win.debug().show_dirty_rects = true;
win.debug().show_click_markers = true;
win.debug().show_widget_bounds = true;
win.debug().log_to_console = true;
// Увеличить размер лога
win.debug().max_log_size = 30;
// Ручное управление dirty region
win.mark_dirty(100, 100, 200, 50); // пометить область
win.mark_all_dirty(); // пометить весь экран
// Чтение состояния отладки
std::cout << "FPS: " << win.debug().fps << "\n";
std::cout << "Mouse: " << win.debug().mouse_x
<< "," << win.debug().mouse_y << "\n";</code></pre>
</div>
<h3>Структура DebugInfo</h3>
<div class="code-wrapper">
<pre><code class="language-cpp">struct DebugInfo {
int fps; // текущий FPS
int widget_count; // количество виджетов
int partial_updates; // счётчик dirty updates
int mouse_x, mouse_y; // координаты мыши
bool show_debug_overlay; // F1
bool show_dirty_rects; // F2
bool show_click_markers; // F3
bool show_widget_bounds; // F4
bool log_to_console; // F5
std::deque&lt;std::string&gt; log; // лог событий
size_t max_log_size; // макс размер лога
};</code></pre>
</div>
</section>
<section id="eventbus"> <section id="eventbus">
<h2>📡 EventBus</h2> <h2>📡 EventBus</h2>
<p>Глобальная шина событий для слабой связи между компонентами. Реализована как Singleton.</p> <p>Глобальная шина событий для слабой связи между компонентами. Поддерживает глобальное логирование всех событий.</p>
<div class="code-wrapper"> <div class="code-wrapper">
<div class="code-header"><span>Использование EventBus</span><button class="copy-btn" onclick="copyCode(this)">Копировать</button></div> <div class="code-header"><span>Работа с EventBus</span></div>
<pre><code class="language-cpp">// Подписка на событие <pre><code class="language-cpp">// Подписка
int token = gui::EventBus::get().on("slider.change", [](const gui::EventData& e) { int token = gui::EventBus::get().on("button.click", [](const gui::EventData& e) {
std::cout << "Widget: " << e.source_id << ", Value: " << e.value << std::endl; std::cout << "Button: " << e.source_id << "\n";
}); });
// Генерация события (обычно делается внутри библиотеки, но можно и вручную) // Отправка
gui::EventBus::get().emit("custom.event", {"widget_id", "some text", 0.5f, 0, true}); gui::EventBus::get().emit("custom.event", {
"widget_id", // source_id
"text value", // text
0.5f, // value
3, // index
true // flag
});
// Отписка // Отписка
gui::EventBus::get().off(token);</code></pre> gui::EventBus::get().off(token);</code></pre>
</div> </div>
<p>Структура <code>EventData</code> содержит: <code>source_id</code> (ID виджета), <code>text</code>, <code>value</code> (для слайдеров/прогресса), <code>index</code> (для списков), <code>flag</code> (для чекбоксов).</p>
<h3>Встроенные события</h3>
<table>
<thead><tr><th>Событие</th><th>Когда возникает</th><th>Данные</th></tr></thead>
<tbody>
<tr><td><code>button.click</code></td><td>Нажатие кнопки</td><td>source_id, text</td></tr>
<tr><td><code>checkbox.change</code></td><td>Изменение чекбокса</td><td>source_id, text, flag</td></tr>
<tr><td><code>radio.change</code></td><td>Выбор радио-кнопки</td><td>source_id, text, flag</td></tr>
<tr><td><code>slider.change</code></td><td>Движение слайдера</td><td>source_id, value (0-1)</td></tr>
<tr><td><code>list.select</code></td><td>Выбор в списке</td><td>source_id, text, index</td></tr>
<tr><td><code>dropdown.select</code></td><td>Выбор в dropdown</td><td>source_id, text, index</td></tr>
<tr><td><code>tree.toggle</code></td><td>Раскрытие узла</td><td>source_id, text, flag</td></tr>
<tr><td><code>input.submit</code></td><td>Enter в Input</td><td>source_id, text</td></tr>
<tr><td><code>page.open</code></td><td>Открытие страницы</td><td>source_id (name)</td></tr>
</tbody>
</table>
</section> </section>
<section id="rawpicture"> <section id="rawpicture">
<h2>🎨 RawPicture</h2> <h2>🎨 RawPicture</h2>
<p>Класс для программного рендеринга в буфер. Поддерживает 8, 16, 24 и 32-битные форматы.</p> <p>Класс для программного рендеринга графики. Поддерживает 8/16/24/32 бита, загрузку BMP и PPM, и все базовые примитивы.</p>
<ul>
<li><strong>Примитивы:</strong> <code>drawLine</code>, <code>fillRect</code>, <code>drawCircle</code>, <code>fillPolygon</code>, <code>drawText</code>.</li> <div class="code-wrapper">
<li><strong>Загрузка:</strong> <code>load("image.bmp")</code> или <code>load("image.ppm")</code>.</li> <div class="code-header"><span>Пример использования</span></div>
<li><strong>Отображение:</strong> <code>present(display, window, gc, x, y)</code> для вывода на экран X11.</li> <pre><code class="language-cpp">auto pic = std::make_shared&lt;gui::RawPicture&gt;(200, 200);
</ul>
pic->clear(0x1A1A1A);
pic->fillCircle(100, 100, 50, 0xFF0000);
pic->drawText(display, 80, 95, "Hello", 0xFFFFFF);
gui::WidgetData w;
w.id = "image";
w.x = 50; w.y = 150;
w.width = 200; w.height = 200;
w.picture = pic;
page.RawPictureWidget(w);</code></pre>
</div>
<h3>Доступные примитивы</h3>
<table>
<thead><tr><th>Метод</th><th>Описание</th></tr></thead>
<tbody>
<tr><td><code>clear(color)</code></td><td>Очистка цветом</td></tr>
<tr><td><code>drawLine(x0,y0,x1,y1,c)</code></td><td>Линия (алгоритм Брезенхема)</td></tr>
<tr><td><code>drawRect/fillRect(...)</code></td><td>Прямоугольник</td></tr>
<tr><td><code>drawCircle/fillCircle(...)</code></td><td>Окружность/круг</td></tr>
<tr><td><code>drawTriangle/fillTriangle(...)</code></td><td>Треугольник</td></tr>
<tr><td><code>drawPolygon/fillPolygon(...)</code></td><td>Произвольный полигон</td></tr>
<tr><td><code>drawText(...)</code></td><td>Текст (X11 шрифт с масштабированием)</td></tr>
<tr><td><code>load(path)</code></td><td>Загрузка BMP или PPM</td></tr>
<tr><td><code>blit(src,dx,dy)</code></td><td>Копирование из другого RawPicture</td></tr>
</tbody>
</table>
</section> </section>
<section id="widgets"> <section id="widgets">
<h2>🧩 Доступные виджеты</h2> <h2>🧩 Виджеты</h2>
<p>Все виджеты создаются через методы класса <code>combat</code> (или <code>page</code>) путем передачи структуры <code>WidgetData</code>.</p> <p>Все виджеты создаются через фабричные методы класса <code>combat</code> с передачей структуры <code>WidgetData</code>.</p>
<table> <table>
<thead><tr><th>Метод</th><th>Тип</th><th>Описание</th></tr></thead> <thead><tr><th>Метод</th><th>Тип</th><th>Описание</th></tr></thead>
<tbody> <tbody>
<tr><td><code>Button()</code></td><td><code>BUTTON</code></td><td>Стандартная кнопка. Поддерживает <code>on_page_click</code> и <code>on_window_click</code>.</td></tr> <tr><td><code>Button(d)</code></td><td>BUTTON</td><td>Кнопка</td></tr>
<tr><td><code>Label()</code></td><td><code>LABEL</code></td><td>Текстовая метка.</td></tr> <tr><td><code>Label(d)</code></td><td>LABEL</td><td>Текстовая метка</td></tr>
<tr><td><code>Input()</code></td><td><code>INPUT</code></td><td>Поле ввода текста. Перехватывает фокус клавиатуры.</td></tr> <tr><td><code>Input(d)</code></td><td>INPUT</td><td>Поле ввода</td></tr>
<tr><td><code>Checkbox()</code></td><td><code>CHECKBOX</code></td><td>Флажок. Состояние в <code>data.checked</code>.</td></tr> <tr><td><code>Checkbox(d)</code></td><td>CHECKBOX</td><td>Флажок</td></tr>
<tr><td><code>Radiobutton()</code></td><td><code>RADIO</code></td><td>Радиокнопка. Автоматически снимает выделение с других радио-кнопок с тем же <code>id</code> на странице.</td></tr> <tr><td><code>Radiobutton(d)</code></td><td>RADIO</td><td>Радио-кнопка</td></tr>
<tr><td><code>Slider()</code></td><td><code>SLIDER</code></td><td>Ползунок. Значение 0.0 - 1.0 в <code>data.value</code>. Поддерживает перетаскивание.</td></tr> <tr><td><code>Slider(d)</code></td><td>SLIDER</td><td>Ползунок 0-1</td></tr>
<tr><td><code>Progressbar()</code></td><td><code>PROGRESS</code></td><td>Индикатор прогресса. Поддерживает анимацию <code>indeterminate</code>.</td></tr> <tr><td><code>Progressbar(d)</code></td><td>PROGRESS</td><td>Прогресс-бар</td></tr>
<tr><td><code>Listbox()</code></td><td><code>LISTBOX</code></td><td>Список элементов. Элементы задаются через <code>data.items</code>.</td></tr> <tr><td><code>Listbox(d)</code></td><td>LISTBOX</td><td>Список</td></tr>
<tr><td><code>Dropdown()</code></td><td><code>DROPDOWN</code></td><td>Выпадающий список с анимацией открытия.</td></tr> <tr><td><code>Dropdown(d)</code></td><td>DROPDOWN</td><td>Выпадающий список</td></tr>
<tr><td><code>TreeView()</code></td><td><code>TREE_VIEW</code></td><td>Контейнер для древовидной структуры. Использует <code>TreeNode</code> как детей.</td></tr> <tr><td><code>TreeView(d)</code></td><td>TREE_VIEW</td><td>Дерево</td></tr>
<tr><td><code>ScrollView()</code></td><td><code>SCROLL</code></td><td>Область с прокруткой содержимого.</td></tr> <tr><td><code>TreeNode(d)</code></td><td>TREE</td><td>Узел дерева</td></tr>
<tr><td><code>RawPictureWidget()</code></td><td><code>RAW_PIC</code></td><td>Отображает объект <code>RawPicture</code> из <code>data.picture</code>.</td></tr> <tr><td><code>ScrollView(d)</code></td><td>SCROLL</td><td>Контейнер с прокруткой</td></tr>
<tr><td><code>RawPictureWidget(d)</code></td><td>RAW_PIC</td><td>Изображение</td></tr>
<tr><td><code>SpriteButton(d)</code></td><td>SPRITE_BTN</td><td>Кнопка со спрайтом</td></tr>
</tbody> </tbody>
</table> </table>
</section> </section>
<section id="api-window"> <section id="api-window">
<h2>📚 API Справочник: gui::window</h2> <h2>📚 API: gui::window</h2>
<details> <details>
<summary><code>window(std::string title)</code></summary> <summary><code>window(std::string title)</code></summary>
<div class="details-content"> <div class="details-content">
<p>Конструктор. Инициализирует соединение с X11, создает окно заданного размера (по умолчанию 1200x600) и настраивает маску событий.</p> <p>Конструктор. Создаёт X11 окно 1200x600, инициализирует backbuffer, настраивает глобальный логгер EventBus.</p>
</div> </div>
</details> </details>
<details> <details>
<summary><code>void update()</code></summary> <summary><code>void update()</code></summary>
<div class="details-content"> <div class="details-content">
<p>Главный метод цикла. Обрабатывает все накопленные события X11, обновляет анимации виджетов (<code>tick</code>), очищает окно и перерисовывает вкладки и активную страницу. <strong>Должен вызываться постоянно.</strong></p> <p>Главный метод цикла. Обрабатывает X11 события, обновляет анимации, перерисовывает dirty regions, обновляет debug overlay. Должен вызываться постоянно.</p>
</div> </div>
</details> </details>
<details> <details>
<summary><code>void addPAGE(std::string name)</code> / <code>void configur_page(...)</code></summary> <summary><code>void addPAGE(name)</code> / <code>configur_page(...)</code></summary>
<div class="details-content"> <div class="details-content">
<p><code>addPAGE</code> создает пустую страницу. <code>configur_page</code> создает (если нет), применяет лямбда-функцию для наполнения виджетами и может сделать её активной (<code>active = true</code>).</p> <p>Создание и настройка страниц с виджетами через callback.</p>
</div> </div>
</details> </details>
<details> <details>
<summary><code>void openPAGE(std::string name)</code></summary> <summary><code>void openPAGE(name)</code></summary>
<div class="details-content"> <div class="details-content">
<p>Делает указанную страницу активной, деактивируя остальные. Генерирует событие <code>"page.open"</code>.</p> <p>Переключение активной страницы. Помечает весь экран как dirty.</p>
</div>
</details>
<details>
<summary><code>DebugInfo& debug()</code> <span class="badge new">NEW</span></summary>
<div class="details-content">
<p>Доступ к отладочной информации: FPS, координаты, режимы, лог событий.</p>
</div>
</details>
<details>
<summary><code>void mark_dirty(x,y,w,h)</code> / <code>mark_all_dirty()</code> <span class="badge new">NEW</span></summary>
<div class="details-content">
<p>Ручное управление dirty region для принудительной перерисовки.</p>
</div> </div>
</details> </details>
</section> </section>
<section id="api-page">
<h2>📚 API: gui::page</h2>
<p>Наследуется от <code>combat</code>, предоставляет все фабричные методы для создания виджетов. Имеет поля <code>width</code>, <code>height</code>, <code>active</code>.</p>
</section>
<section id="api-combat"> <section id="api-combat">
<h2>📚 API Справочник: gui::combat</h2> <h2>📚 API: gui::combat</h2>
<p>Базовый класс для контейнеров. Все методы создания виджетов возвращают ссылку на созданный <code>Widget</code>, что позволяет сохранять его для последующего изменения.</p>
<details> <details>
<summary>Фабричные методы (<code>Button</code>, <code>Label</code>, <code>Input</code> и т.д.)</summary> <summary>Фабричные методы</summary>
<div class="details-content"> <div class="details-content">
<p>Принимают объект <code>WidgetData</code>. Автоматически устанавливают соответствующий <code>WidgetType</code>, добавляют виджет во внутренний вектор и возвращают на него ссылку.</p> <p>14 методов для создания виджетов: Button, Label, Input, Checkbox, Radiobutton, Slider, Progressbar, Listbox, Dropdown, TreeView, TreeNode, ScrollView, RawPictureWidget, SpriteButton.</p>
</div> </div>
</details> </details>
<details> <details>
<summary><code>Widget* find(const std::string& id)</code></summary> <summary><code>Widget* find(const std::string& id)</code></summary>
<div class="details-content"> <div class="details-content">
<p>Рекурсивный поиск виджета по его уникальному идентификатору <code>id</code> внутри контейнера и всех его дочерних элементов.</p> <p>Рекурсивный поиск виджета по ID в иерархии.</p>
</div> </div>
</details> </details>
<details> <details>
<summary><code>void visit(const std::function<void(Widget&)>& fn)</code></summary> <summary><code>void visit(fn)</code></summary>
<div class="details-content"> <div class="details-content">
<p>Применяет переданную лямбда-функцию ко всем виджетам в иерархии. Удобно для массовой модификации (например, отключения всех кнопок).</p> <p>Обход всех виджетов с применением лямбда-функции.</p>
</div>
</details>
<details>
<summary><code>int count_widgets()</code> <span class="badge new">NEW</span></summary>
<div class="details-content">
<p>Рекурсивный подсчёт всех виджетов в иерархии.</p>
</div> </div>
</details> </details>
</section> </section>
<section id="api-widget"> <section id="api-widget">
<h2>📚 API Справочник: gui::Widget</h2> <h2>📚 API: gui::Widget</h2>
<details> <details>
<summary><code>void setValue(float v)</code> / <code>float getValue()</code></summary> <summary><code>void setValue(float v)</code> / <code>getValue()</code></summary>
<div class="details-content"> <div class="details-content">
<p>Устанавливает целевое значение. Для прогресс-баров и слайдеров это запускает плавную анимацию изменения <code>data.value</code> к <code>data.target_value</code> внутри метода <code>tick()</code>.</p> <p>Установка целевого значения с плавной анимацией перехода.</p>
</div> </div>
</details> </details>
<details> <details>
<summary>Анимация и состояние</summary> <summary><code>void mark_dirty(dirty, ox, oy)</code> <span class="badge new">NEW</span></summary>
<div class="details-content"> <div class="details-content">
<p>Виджет содержит поля <code>anim</code> (для dropdown), <code>phase</code> (для неопределенного прогресса). Метод <code>tick(float dt)</code> автоматически вызывается из <code>window::update()</code> и интерполирует значения.</p> <p>Помечает область виджета как dirty для частичной перерисовки.</p>
</div>
</details>
<details>
<summary>Автоматическая оптимизация</summary>
<div class="details-content">
<p>При изменении состояния виджет сам помечает свою область. Для составных виджетов (dropdown с popup) помечаются все связанные области.</p>
</div> </div>
</details> </details>
</section>
<section id="tips">
<h2>💡 Советы и лучшие практики</h2>
<ul>
<li><strong>Производительность:</strong> Библиотека использует программный рендеринг (CPU). Для сложных сцен избегайте частого пересоздания <code>RawPicture</code>. Используйте <code>blit</code> для кеширования отрисовки.</li>
<li><strong>ID Виджетов:</strong> Всегда задавайте уникальное поле <code>id</code> в <code>WidgetData</code>, если планируете обращаться к виджету позже или слушать его события.</li>
<li><strong>Вложенность:</strong> Виджеты <code>TreeView</code> и <code>ScrollView</code> предназначены для содержания других виджетов. Добавляйте их через стандартные методы, они будут учитываться при расчете высоты контента и прокрутки.</li>
<li><strong>Цвета:</strong> Указываются в формате HEX (например, <code>0xFF0000</code> для красного). Библиотека автоматически преобразует их в формат пикселей X11 при отрисовке.</li>
</ul>
</section> </section>
<footer style="margin-top: 4rem; padding-top: 2rem; border-top: 1px solid var(--border); color: var(--text-secondary); text-align: center; font-size: 0.9rem;"> <footer style="margin-top: 4rem; padding-top: 2rem; border-top: 1px solid var(--border); color: var(--text-secondary); text-align: center; font-size: 0.9rem;">
<p>Сгенерировано для X11 C++ GUI Library. 2026</p> <p>X11 GUI Library v2.0 • Made with ❤️ for KoDer</p>
<p style="margin-top: 0.5rem;">GitLab: <a href="https://git.bipfr.ru/KoDer/gui" style="color: var(--accent);">git.bipfr.ru/KoDer/gui</a></p>
</footer> </footer>
</main> </main>
<!-- Скрипты -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-cpp.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-cpp.min.js"></script>
<script> <script>
// Функция копирования кода
function copyCode(button) { function copyCode(button) {
const codeBlock = button.parentElement.nextElementSibling.querySelector('code'); const codeBlock = button.parentElement.nextElementSibling.querySelector('code');
const text = codeBlock.innerText; const text = codeBlock.innerText;
navigator.clipboard.writeText(text).then(() => { navigator.clipboard.writeText(text).then(() => {
const originalText = button.innerText; const originalText = button.innerText;
button.innerText = 'Скопировано!'; button.innerText = '✓ Скопировано!';
button.classList.add('copied'); button.classList.add('copied');
setTimeout(() => { setTimeout(() => {
button.innerText = originalText; button.innerText = originalText;
button.classList.remove('copied'); button.classList.remove('copied');
@ -464,36 +747,23 @@ gui::EventBus::get().off(token);</code></pre>
}); });
} }
// Поиск по документации
const searchInput = document.getElementById('searchInput'); const searchInput = document.getElementById('searchInput');
const sections = document.querySelectorAll('section'); const sections = document.querySelectorAll('section');
const navLinks = document.querySelectorAll('.nav-link'); const navLinks = document.querySelectorAll('.nav-link');
searchInput.addEventListener('input', (e) => { searchInput.addEventListener('input', (e) => {
const term = e.target.value.toLowerCase(); const term = e.target.value.toLowerCase();
sections.forEach(section => { sections.forEach(section => {
const text = section.innerText.toLowerCase(); const text = section.innerText.toLowerCase();
if (text.includes(term)) { section.style.display = (term === '' || text.includes(term)) ? 'block' : 'none';
section.style.display = 'block';
} else {
section.style.display = term === '' ? 'block' : 'none';
}
}); });
// Подсветка активных ссылок в сайдбаре
navLinks.forEach(link => { navLinks.forEach(link => {
const targetId = link.getAttribute('href').substring(1); const targetId = link.getAttribute('href').substring(1);
const targetSection = document.getElementById(targetId); const targetSection = document.getElementById(targetId);
if (targetSection && targetSection.style.display === 'none') { link.style.display = (targetSection && targetSection.style.display === 'none') ? 'none' : 'block';
link.style.display = 'none';
} else {
link.style.display = 'block';
}
}); });
}); });
// Плавная прокрутка и активный класс
navLinks.forEach(link => { navLinks.forEach(link => {
link.addEventListener('click', (e) => { link.addEventListener('click', (e) => {
navLinks.forEach(l => l.classList.remove('active')); navLinks.forEach(l => l.classList.remove('active'));
@ -504,12 +774,13 @@ gui::EventBus::get().off(token);</code></pre>
window.addEventListener('scroll', () => { window.addEventListener('scroll', () => {
let current = ''; let current = '';
sections.forEach(section => { sections.forEach(section => {
const sectionTop = section.offsetTop; if (section.style.display !== 'none') {
if (pageYOffset >= sectionTop - 100) { const sectionTop = section.offsetTop;
current = section.getAttribute('id'); if (pageYOffset >= sectionTop - 100) {
current = section.getAttribute('id');
}
} }
}); });
navLinks.forEach(link => { navLinks.forEach(link => {
link.classList.remove('active'); link.classList.remove('active');
if (link.getAttribute('href').substring(1) === current) { if (link.getAttribute('href').substring(1) === current) {