gui/docs.html
2026-08-24 11:10:00 +00:00

793 lines
37 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
## 📄 `docs/index.html` (обновлённая HTML-документация)
```html
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<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 rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
<style>
:root {
--bg-primary: #0f172a;
--bg-secondary: #1e293b;
--bg-tertiary: #334155;
--text-primary: #f1f5f9;
--text-secondary: #94a3b8;
--accent: #38bdf8;
--accent-hover: #0ea5e9;
--success: #22c55e;
--warning: #f59e0b;
--danger: #ef4444;
--border: #334155;
--code-bg: #0d1117;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Inter', sans-serif;
background-color: var(--bg-primary);
color: var(--text-primary);
line-height: 1.6;
display: flex;
min-height: 100vh;
}
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: var(--bg-primary); }
::-webkit-scrollbar-thumb { background: var(--bg-tertiary); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: var(--accent); }
.sidebar {
width: 280px;
background-color: var(--bg-secondary);
border-right: 1px solid var(--border);
position: fixed;
height: 100vh;
overflow-y: auto;
padding: 2rem 1.5rem;
z-index: 100;
}
.logo {
font-size: 1.5rem;
font-weight: 700;
color: var(--accent);
margin-bottom: 2rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.search-box {
width: 100%;
padding: 0.75rem;
background: var(--bg-primary);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-primary);
font-family: 'Inter', sans-serif;
margin-bottom: 1.5rem;
outline: none;
transition: border-color 0.2s;
}
.search-box:focus { border-color: var(--accent); }
.nav-group { margin-bottom: 1.5rem; }
.nav-title {
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--text-secondary);
margin-bottom: 0.5rem;
font-weight: 600;
}
.nav-link {
display: block;
padding: 0.5rem 0.75rem;
color: var(--text-secondary);
text-decoration: none;
border-radius: 6px;
font-size: 0.9rem;
transition: all 0.2s;
}
.nav-link:hover, .nav-link.active {
background-color: var(--bg-tertiary);
color: var(--accent);
}
.main-content {
margin-left: 280px;
flex: 1;
padding: 3rem 4rem;
max-width: 1200px;
}
h1 { font-size: 2.5rem; margin-bottom: 1rem; color: var(--text-primary); }
h2 { font-size: 1.8rem; margin-top: 3rem; margin-bottom: 1rem; color: var(--accent); border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; }
h3 { font-size: 1.3rem; margin-top: 2rem; margin-bottom: 0.75rem; color: var(--text-primary); }
p { margin-bottom: 1rem; color: var(--text-secondary); }
.badge {
display: inline-block;
padding: 0.25rem 0.5rem;
background: var(--bg-tertiary);
color: var(--accent);
border-radius: 4px;
font-size: 0.75rem;
font-family: 'JetBrains Mono', monospace;
margin-right: 0.5rem;
}
.badge.new { background: var(--success); color: white; }
.badge.warning { background: var(--warning); color: black; }
.code-wrapper {
position: relative;
margin: 1.5rem 0;
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--border);
}
.code-header {
background: var(--bg-secondary);
padding: 0.5rem 1rem;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid var(--border);
font-size: 0.85rem;
color: var(--text-secondary);
}
.copy-btn {
background: transparent;
border: 1px solid var(--border);
color: var(--text-secondary);
padding: 0.25rem 0.75rem;
border-radius: 4px;
cursor: pointer;
font-size: 0.8rem;
transition: all 0.2s;
}
.copy-btn:hover { background: var(--bg-tertiary); color: var(--text-primary); }
.copy-btn.copied { border-color: var(--success); color: var(--success); }
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; }
table {
width: 100%;
border-collapse: collapse;
margin: 1.5rem 0;
background: var(--bg-secondary);
border-radius: 8px;
overflow: hidden;
}
th, td {
padding: 1rem;
text-align: left;
border-bottom: 1px solid var(--border);
}
th { background: var(--bg-tertiary); color: var(--text-primary); font-weight: 600; }
td { color: var(--text-secondary); }
td code { background: var(--bg-primary); padding: 0.2rem 0.4rem; border-radius: 4px; color: var(--accent); }
details {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
margin-bottom: 1rem;
overflow: hidden;
}
summary {
padding: 1rem;
cursor: pointer;
font-weight: 600;
color: var(--text-primary);
list-style: none;
display: flex;
justify-content: space-between;
align-items: center;
}
summary::-webkit-details-marker { display: none; }
summary::after { content: '+'; font-size: 1.5rem; color: var(--accent); }
details[open] summary::after { content: '−'; }
details[open] summary { border-bottom: 1px solid var(--border); }
.details-content { padding: 1.5rem; }
.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) {
.sidebar { transform: translateX(-100%); transition: transform 0.3s; }
.sidebar.open { transform: translateX(0); }
.main-content { margin-left: 0; padding: 2rem; }
}
</style>
</head>
<body>
<nav class="sidebar">
<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>
X11 GUI Lib
</div>
<input type="text" class="search-box" placeholder="Поиск..." id="searchInput">
<div class="nav-group">
<div class="nav-title">Начало</div>
<a href="#intro" class="nav-link">Введение</a>
<a href="#features" class="nav-link">Возможности</a>
<a href="#quickstart" class="nav-link">Быстрый старт</a>
</div>
<div class="nav-group">
<div class="nav-title">Компоненты</div>
<a href="#eventbus" class="nav-link">EventBus</a>
<a href="#rawpicture" class="nav-link">RawPicture</a>
<a href="#widgets" class="nav-link">Виджеты</a>
</div>
<div class="nav-group">
<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-page" class="nav-link">gui::page</a>
<a href="#api-combat" class="nav-link">gui::combat</a>
<a href="#api-widget" class="nav-link">gui::Widget</a>
</div>
</nav>
<main class="main-content">
<section id="intro">
<h1>📘 X11 GUI Library</h1>
<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 id="quickstart">
<h2>🚀 Быстрый старт</h2>
<div class="code-wrapper">
<div class="code-header">
<span>main.cpp</span>
<button class="copy-btn" onclick="copyCode(this)">Копировать</button>
</div>
<pre><code class="language-cpp">#include "gui.h"
int main() {
gui::window win("My App");
win.addPAGE("main");
win.configur_page("main", [](gui::page& p) {
gui::WidgetData btn;
btn.id = "start_btn";
btn.text = "Start";
btn.x = 50; btn.y = 50;
btn.width = 150; btn.height = 40;
btn.bg_color = 0x2563EB;
p.Button(btn);
}, true);
// Включить все режимы отладки
win.debug().show_debug_overlay = true;
win.debug().show_dirty_rects = true;
win.debug().log_to_console = true;
gui::EventBus::get().on("button.click", [](const gui::EventData& e) {
std::cout << "Clicked: " << e.source_id << "\n";
});
while (true) {
win.update();
}
return 0;
}</code></pre>
</div>
</section>
<section id="dirty-rects">
<h2>⚡ Dirty Rectangles <span class="badge new">NEW</span></h2>
<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>
<thead>
<tr><th>Показатель</th><th>Описание</th></tr>
</thead>
<tbody>
<tr><td><code>FPS</code></td><td>Текущий FPS (обновляется каждые 0.5 сек)</td></tr>
<tr><td><code>Widgets</code></td><td>Общее количество виджетов на всех страницах</td></tr>
<tr><td><code>Partial updates</code></td><td>Счётчик частичных обновлений (показывает эффективность dirty rects)</td></tr>
<tr><td><code>Mouse</code></td><td>Текущие координаты мыши</td></tr>
<tr><td><code>Event Log</code></td><td>Последние 5 событий с полной информацией</td></tr>
</tbody>
</table>
</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">
<h2>📡 EventBus</h2>
<p>Глобальная шина событий для слабой связи между компонентами. Поддерживает глобальное логирование всех событий.</p>
<div class="code-wrapper">
<div class="code-header"><span>Работа с EventBus</span></div>
<pre><code class="language-cpp">// Подписка
int token = gui::EventBus::get().on("button.click", [](const gui::EventData& e) {
std::cout << "Button: " << e.source_id << "\n";
});
// Отправка
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>
</div>
<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 id="rawpicture">
<h2>🎨 RawPicture</h2>
<p>Класс для программного рендеринга графики. Поддерживает 8/16/24/32 бита, загрузку BMP и PPM, и все базовые примитивы.</p>
<div class="code-wrapper">
<div class="code-header"><span>Пример использования</span></div>
<pre><code class="language-cpp">auto pic = std::make_shared&lt;gui::RawPicture&gt;(200, 200);
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 id="widgets">
<h2>🧩 Виджеты</h2>
<p>Все виджеты создаются через фабричные методы класса <code>combat</code> с передачей структуры <code>WidgetData</code>.</p>
<table>
<thead><tr><th>Метод</th><th>Тип</th><th>Описание</th></tr></thead>
<tbody>
<tr><td><code>Button(d)</code></td><td>BUTTON</td><td>Кнопка</td></tr>
<tr><td><code>Label(d)</code></td><td>LABEL</td><td>Текстовая метка</td></tr>
<tr><td><code>Input(d)</code></td><td>INPUT</td><td>Поле ввода</td></tr>
<tr><td><code>Checkbox(d)</code></td><td>CHECKBOX</td><td>Флажок</td></tr>
<tr><td><code>Radiobutton(d)</code></td><td>RADIO</td><td>Радио-кнопка</td></tr>
<tr><td><code>Slider(d)</code></td><td>SLIDER</td><td>Ползунок 0-1</td></tr>
<tr><td><code>Progressbar(d)</code></td><td>PROGRESS</td><td>Прогресс-бар</td></tr>
<tr><td><code>Listbox(d)</code></td><td>LISTBOX</td><td>Список</td></tr>
<tr><td><code>Dropdown(d)</code></td><td>DROPDOWN</td><td>Выпадающий список</td></tr>
<tr><td><code>TreeView(d)</code></td><td>TREE_VIEW</td><td>Дерево</td></tr>
<tr><td><code>TreeNode(d)</code></td><td>TREE</td><td>Узел дерева</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>
</table>
</section>
<section id="api-window">
<h2>📚 API: gui::window</h2>
<details>
<summary><code>window(std::string title)</code></summary>
<div class="details-content">
<p>Конструктор. Создаёт X11 окно 1200x600, инициализирует backbuffer, настраивает глобальный логгер EventBus.</p>
</div>
</details>
<details>
<summary><code>void update()</code></summary>
<div class="details-content">
<p>Главный метод цикла. Обрабатывает X11 события, обновляет анимации, перерисовывает dirty regions, обновляет debug overlay. Должен вызываться постоянно.</p>
</div>
</details>
<details>
<summary><code>void addPAGE(name)</code> / <code>configur_page(...)</code></summary>
<div class="details-content">
<p>Создание и настройка страниц с виджетами через callback.</p>
</div>
</details>
<details>
<summary><code>void openPAGE(name)</code></summary>
<div class="details-content">
<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>
</details>
</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">
<h2>📚 API: gui::combat</h2>
<details>
<summary>Фабричные методы</summary>
<div class="details-content">
<p>14 методов для создания виджетов: Button, Label, Input, Checkbox, Radiobutton, Slider, Progressbar, Listbox, Dropdown, TreeView, TreeNode, ScrollView, RawPictureWidget, SpriteButton.</p>
</div>
</details>
<details>
<summary><code>Widget* find(const std::string& id)</code></summary>
<div class="details-content">
<p>Рекурсивный поиск виджета по ID в иерархии.</p>
</div>
</details>
<details>
<summary><code>void visit(fn)</code></summary>
<div class="details-content">
<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>
</details>
</section>
<section id="api-widget">
<h2>📚 API: gui::Widget</h2>
<details>
<summary><code>void setValue(float v)</code> / <code>getValue()</code></summary>
<div class="details-content">
<p>Установка целевого значения с плавной анимацией перехода.</p>
</div>
</details>
<details>
<summary><code>void mark_dirty(dirty, ox, oy)</code> <span class="badge new">NEW</span></summary>
<div class="details-content">
<p>Помечает область виджета как dirty для частичной перерисовки.</p>
</div>
</details>
<details>
<summary>Автоматическая оптимизация</summary>
<div class="details-content">
<p>При изменении состояния виджет сам помечает свою область. Для составных виджетов (dropdown с popup) помечаются все связанные области.</p>
</div>
</details>
</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;">
<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>
</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/components/prism-cpp.min.js"></script>
<script>
function copyCode(button) {
const codeBlock = button.parentElement.nextElementSibling.querySelector('code');
const text = codeBlock.innerText;
navigator.clipboard.writeText(text).then(() => {
const originalText = button.innerText;
button.innerText = '✓ Скопировано!';
button.classList.add('copied');
setTimeout(() => {
button.innerText = originalText;
button.classList.remove('copied');
}, 2000);
});
}
const searchInput = document.getElementById('searchInput');
const sections = document.querySelectorAll('section');
const navLinks = document.querySelectorAll('.nav-link');
searchInput.addEventListener('input', (e) => {
const term = e.target.value.toLowerCase();
sections.forEach(section => {
const text = section.innerText.toLowerCase();
section.style.display = (term === '' || text.includes(term)) ? 'block' : 'none';
});
navLinks.forEach(link => {
const targetId = link.getAttribute('href').substring(1);
const targetSection = document.getElementById(targetId);
link.style.display = (targetSection && targetSection.style.display === 'none') ? 'none' : 'block';
});
});
navLinks.forEach(link => {
link.addEventListener('click', (e) => {
navLinks.forEach(l => l.classList.remove('active'));
link.classList.add('active');
});
});
window.addEventListener('scroll', () => {
let current = '';
sections.forEach(section => {
if (section.style.display !== 'none') {
const sectionTop = section.offsetTop;
if (pageYOffset >= sectionTop - 100) {
current = section.getAttribute('id');
}
}
});
navLinks.forEach(link => {
link.classList.remove('active');
if (link.getAttribute('href').substring(1) === current) {
link.classList.add('active');
}
});
});
</script>
</body>
</html>