gui/docs.html
2026-08-25 01:40:01 +07:00

522 lines
27 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.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>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;
--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;
}
/* Блоки кода */
.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); }
/* Аккордеон для API */
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; }
@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="#quickstart" class="nav-link">Быстрый старт</a>
<a href="#architecture" 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">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>Документация GUI Библиотеки</h1>
<p>Легковесная, кроссплатформенная (X11) библиотека для создания графических интерфейсов на C++. Поддерживает программный рендеринг, анимации, иерархию виджетов и событийно-ориентированную архитектуру.</p>
</section>
<section id="quickstart">
<h2>🚀 Быстрый старт</h2>
<p>Минимальный пример создания окна с кнопкой и обработкой события.</p>
<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() {
// 1. Создаем окно
gui::window win("Мое Приложение");
// 2. Добавляем страницу
win.addPAGE("main");
// 3. Настраиваем страницу виджетами
win.configur_page("main", [](gui::page& p) {
// Создаем кнопку
gui::WidgetData btnData;
btnData.id = "my_button";
btnData.text = "Нажми меня!";
btnData.x = 50; btnData.y = 50;
btnData.width = 150; btnData.height = 40;
btnData.bg_color = 0x2563EB; // Синий
btnData.fg_color = 0xFFFFFF; // Белый текст
p.Button(btnData);
}, true); // true = сделать активной сразу
// 4. Подписываемся на событие
gui::EventBus::get().on("button.click", [](const gui::EventData& e) {
if (e.source_id == "my_button") {
std::cout << "Кнопка нажата!" << std::endl;
}
});
// 5. Главный цикл
while (true) {
win.update(); // Обработка событий X11 и отрисовка
// Добавьте std::this_thread::sleep_for для экономии CPU
}
return 0;
}</code></pre>
</div>
</section>
<section id="architecture">
<h2>🏛 Архитектура</h2>
<p>Библиотека построена на строгой иерархии:</p>
<table>
<thead>
<tr><th>Уровень</th><th>Класс</th><th>Описание</th></tr>
</thead>
<tbody>
<tr><td><span class="badge">1</span></td><td><code>gui::window</code></td><td>Управляет соединением с X11, главным циклом (`update`) и вкладками.</td></tr>
<tr><td><span class="badge">2</span></td><td><code>gui::page</code></td><td>Представляет собой вкладку или экран. Наследуется от <code>combat</code>.</td></tr>
<tr><td><span class="badge">3</span></td><td><code>gui::combat</code></td><td>Базовый контейнер. Хранит коллекцию виджетов и предоставляет фабричные методы для их создания.</td></tr>
<tr><td><span class="badge">4</span></td><td><code>gui::Widget</code></td><td>Конкретный элемент интерфейса (кнопка, ввод, слайдер). Также наследуется от <code>combat</code>, позволяя создавать вложенные структуры (например, деревья).</td></tr>
</tbody>
</table>
</section>
<section id="eventbus">
<h2>📡 EventBus</h2>
<p>Глобальная шина событий для слабой связи между компонентами. Реализована как Singleton.</p>
<div class="code-wrapper">
<div class="code-header"><span>Использование EventBus</span><button class="copy-btn" onclick="copyCode(this)">Копировать</button></div>
<pre><code class="language-cpp">// Подписка на событие
int token = gui::EventBus::get().on("slider.change", [](const gui::EventData& e) {
std::cout << "Widget: " << e.source_id << ", Value: " << e.value << std::endl;
});
// Генерация события (обычно делается внутри библиотеки, но можно и вручную)
gui::EventBus::get().emit("custom.event", {"widget_id", "some text", 0.5f, 0, true});
// Отписка
gui::EventBus::get().off(token);</code></pre>
</div>
<p>Структура <code>EventData</code> содержит: <code>source_id</code> (ID виджета), <code>text</code>, <code>value</code> (для слайдеров/прогресса), <code>index</code> (для списков), <code>flag</code> (для чекбоксов).</p>
</section>
<section id="rawpicture">
<h2>🎨 RawPicture</h2>
<p>Класс для программного рендеринга в буфер. Поддерживает 8, 16, 24 и 32-битные форматы.</p>
<ul>
<li><strong>Примитивы:</strong> <code>drawLine</code>, <code>fillRect</code>, <code>drawCircle</code>, <code>fillPolygon</code>, <code>drawText</code>.</li>
<li><strong>Загрузка:</strong> <code>load("image.bmp")</code> или <code>load("image.ppm")</code>.</li>
<li><strong>Отображение:</strong> <code>present(display, window, gc, x, y)</code> для вывода на экран X11.</li>
</ul>
</section>
<section id="widgets">
<h2>🧩 Доступные виджеты</h2>
<p>Все виджеты создаются через методы класса <code>combat</code> (или <code>page</code>) путем передачи структуры <code>WidgetData</code>.</p>
<table>
<thead><tr><th>Метод</th><th>Тип</th><th>Описание</th></tr></thead>
<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>Label()</code></td><td><code>LABEL</code></td><td>Текстовая метка.</td></tr>
<tr><td><code>Input()</code></td><td><code>INPUT</code></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>Radiobutton()</code></td><td><code>RADIO</code></td><td>Радиокнопка. Автоматически снимает выделение с других радио-кнопок с тем же <code>id</code> на странице.</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>Progressbar()</code></td><td><code>PROGRESS</code></td><td>Индикатор прогресса. Поддерживает анимацию <code>indeterminate</code>.</td></tr>
<tr><td><code>Listbox()</code></td><td><code>LISTBOX</code></td><td>Список элементов. Элементы задаются через <code>data.items</code>.</td></tr>
<tr><td><code>Dropdown()</code></td><td><code>DROPDOWN</code></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>ScrollView()</code></td><td><code>SCROLL</code></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>
</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) и настраивает маску событий.</p>
</div>
</details>
<details>
<summary><code>void update()</code></summary>
<div class="details-content">
<p>Главный метод цикла. Обрабатывает все накопленные события X11, обновляет анимации виджетов (<code>tick</code>), очищает окно и перерисовывает вкладки и активную страницу. <strong>Должен вызываться постоянно.</strong></p>
</div>
</details>
<details>
<summary><code>void addPAGE(std::string name)</code> / <code>void configur_page(...)</code></summary>
<div class="details-content">
<p><code>addPAGE</code> создает пустую страницу. <code>configur_page</code> создает (если нет), применяет лямбда-функцию для наполнения виджетами и может сделать её активной (<code>active = true</code>).</p>
</div>
</details>
<details>
<summary><code>void openPAGE(std::string name)</code></summary>
<div class="details-content">
<p>Делает указанную страницу активной, деактивируя остальные. Генерирует событие <code>"page.open"</code>.</p>
</div>
</details>
</section>
<section id="api-combat">
<h2>📚 API Справочник: gui::combat</h2>
<p>Базовый класс для контейнеров. Все методы создания виджетов возвращают ссылку на созданный <code>Widget</code>, что позволяет сохранять его для последующего изменения.</p>
<details>
<summary>Фабричные методы (<code>Button</code>, <code>Label</code>, <code>Input</code> и т.д.)</summary>
<div class="details-content">
<p>Принимают объект <code>WidgetData</code>. Автоматически устанавливают соответствующий <code>WidgetType</code>, добавляют виджет во внутренний вектор и возвращают на него ссылку.</p>
</div>
</details>
<details>
<summary><code>Widget* find(const std::string& id)</code></summary>
<div class="details-content">
<p>Рекурсивный поиск виджета по его уникальному идентификатору <code>id</code> внутри контейнера и всех его дочерних элементов.</p>
</div>
</details>
<details>
<summary><code>void visit(const std::function<void(Widget&)>& fn)</code></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>float getValue()</code></summary>
<div class="details-content">
<p>Устанавливает целевое значение. Для прогресс-баров и слайдеров это запускает плавную анимацию изменения <code>data.value</code> к <code>data.target_value</code> внутри метода <code>tick()</code>.</p>
</div>
</details>
<details>
<summary>Анимация и состояние</summary>
<div class="details-content">
<p>Виджет содержит поля <code>anim</code> (для dropdown), <code>phase</code> (для неопределенного прогресса). Метод <code>tick(float dt)</code> автоматически вызывается из <code>window::update()</code> и интерполирует значения.</p>
</div>
</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>
<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>
</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();
if (text.includes(term)) {
section.style.display = 'block';
} else {
section.style.display = term === '' ? 'block' : 'none';
}
});
// Подсветка активных ссылок в сайдбаре
navLinks.forEach(link => {
const targetId = link.getAttribute('href').substring(1);
const targetSection = document.getElementById(targetId);
if (targetSection && targetSection.style.display === 'none') {
link.style.display = 'none';
} else {
link.style.display = '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 => {
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>