diff --git a/docs.html b/docs.html
deleted file mode 100644
index 29fedcc..0000000
--- a/docs.html
+++ /dev/null
@@ -1,522 +0,0 @@
-
-
-
-
-
- Документация GUI Библиотеки
- Легковесная, кроссплатформенная (X11) библиотека для создания графических интерфейсов на C++. Поддерживает программный рендеринг, анимации, иерархию виджетов и событийно-ориентированную архитектуру.
-
-
-
- 🚀 Быстрый старт
- Минимальный пример создания окна с кнопкой и обработкой события.
-
-
-
#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;
-}
-
-
-
-
- 🏛 Архитектура
- Библиотека построена на строгой иерархии:
-
-
- | Уровень | Класс | Описание |
-
-
- | 1 | gui::window | Управляет соединением с X11, главным циклом (`update`) и вкладками. |
- | 2 | gui::page | Представляет собой вкладку или экран. Наследуется от combat. |
- | 3 | gui::combat | Базовый контейнер. Хранит коллекцию виджетов и предоставляет фабричные методы для их создания. |
- | 4 | gui::Widget | Конкретный элемент интерфейса (кнопка, ввод, слайдер). Также наследуется от combat, позволяя создавать вложенные структуры (например, деревья). |
-
-
-
-
-
- 📡 EventBus
- Глобальная шина событий для слабой связи между компонентами. Реализована как Singleton.
-
-
-
// Подписка на событие
-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);
-
- Структура EventData содержит: source_id (ID виджета), text, value (для слайдеров/прогресса), index (для списков), flag (для чекбоксов).
-
-
-
- 🎨 RawPicture
- Класс для программного рендеринга в буфер. Поддерживает 8, 16, 24 и 32-битные форматы.
-
- - Примитивы:
drawLine, fillRect, drawCircle, fillPolygon, drawText.
- - Загрузка:
load("image.bmp") или load("image.ppm").
- - Отображение:
present(display, window, gc, x, y) для вывода на экран X11.
-
-
-
-
-
-
- 📚 API Справочник: gui::window
-
- window(std::string title)
-
-
Конструктор. Инициализирует соединение с X11, создает окно заданного размера (по умолчанию 1200x600) и настраивает маску событий.
-
-
-
- void update()
-
-
Главный метод цикла. Обрабатывает все накопленные события X11, обновляет анимации виджетов (tick), очищает окно и перерисовывает вкладки и активную страницу. Должен вызываться постоянно.
-
-
-
- void addPAGE(std::string name) / void configur_page(...)
-
-
addPAGE создает пустую страницу. configur_page создает (если нет), применяет лямбда-функцию для наполнения виджетами и может сделать её активной (active = true).
-
-
-
- void openPAGE(std::string name)
-
-
Делает указанную страницу активной, деактивируя остальные. Генерирует событие "page.open".
-
-
-
-
-
- 📚 API Справочник: gui::combat
- Базовый класс для контейнеров. Все методы создания виджетов возвращают ссылку на созданный Widget, что позволяет сохранять его для последующего изменения.
-
- Фабричные методы (Button, Label, Input и т.д.)
-
-
Принимают объект WidgetData. Автоматически устанавливают соответствующий WidgetType, добавляют виджет во внутренний вектор и возвращают на него ссылку.
-
-
-
- Widget* find(const std::string& id)
-
-
Рекурсивный поиск виджета по его уникальному идентификатору id внутри контейнера и всех его дочерних элементов.
-
-
-
- void visit(const std::function& fn)
-
-
Применяет переданную лямбда-функцию ко всем виджетам в иерархии. Удобно для массовой модификации (например, отключения всех кнопок).
-
-
-
-
-
-
-
- 💡 Советы и лучшие практики
-
- - Производительность: Библиотека использует программный рендеринг (CPU). Для сложных сцен избегайте частого пересоздания
RawPicture. Используйте blit для кеширования отрисовки.
- - ID Виджетов: Всегда задавайте уникальное поле
id в WidgetData, если планируете обращаться к виджету позже или слушать его события.
- - Вложенность: Виджеты
TreeView и ScrollView предназначены для содержания других виджетов. Добавляйте их через стандартные методы, они будут учитываться при расчете высоты контента и прокрутки.
- - Цвета: Указываются в формате HEX (например,
0xFF0000 для красного). Библиотека автоматически преобразует их в формат пикселей X11 при отрисовке.
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000..04c9b81
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,432 @@
+
+
+
+
+
+
+
+Getting Started
+Lightweight X11 GUI library for C++20 with software rendering, dirty-rectangle partial updates, TTF fonts (FreeType), two built-in themes (WIN11 / TERMINAL) and smooth animations.
+
+
Features
+
+- Partial redraw (dirty rectangles) — only changed regions repaint
+- Double buffering — no flicker
+- TTF fonts via FreeType with cached 1-bit masks (fast text)
+- Two themes:
WIN11 and TERMINAL, fully customizable
+- Animations: hover, press, push-down, check, dropdown
+- EventBus + per-widget callbacks
+- Debug overlay, dirty-rect visualization, click markers (F1–F6)
+
+
+Build
+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)
+Quick start
+#include "gui.h"
+int main() {
+ gui::set_theme(gui::ThemeStyle::WIN11);
+ gui::window win("My App");
+ win.set_font("SGr-Iosevka-Regular.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;
+ 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();
+}
+Put SGr-Iosevka-Regular.ttc (or any TTF/TTC) next to the binary. If not found, a fallback X11 core font is used.
+
+
+
+
+Window & Pages
+gui::window
+
+| Method | Description |
+window(title) | Create X11 window (1600×900), backbuffer, load font |
+update() | Process events + render one frame (call in a loop) |
+running() | false after WM_DELETE (close button) |
+set_font(path) | Load TTF/TTC font |
+set_font_size(px) | Global font size (default 32) |
+set_icon(path) / set_icon(pic) / set_default_icon() | Window icon (_NET_WM_ICON) |
+set_max_fps(n) | Frame cap (default 240) |
+on_key | std::function<void(KeySym)> — custom hotkeys (F6+) |
+
+Pages & tabs
+// tabs (left column)
+gui::WidgetData tab; tab.id = "main"; tab.text = "main";
+tab.on_window_click = [&win](gui::window& w){ w.openPAGE("main"); };
+win.addTAB_BUTTON(tab);
+
+// pages
+win.addPAGE("main");
+win.configur_page("main", [](gui::page& p){ /* fill widgets */ }, true);
+win.openPAGE("main");
+Only the active page is ticked and rendered — inactive pages cost zero CPU.
+Finding widgets
+gui::Widget* w = win.find("btn"); // search all pages
+if (w) { w->setValue(0.7f); win.mark_dirty(100,100,300,70); }
+
+
+
+
+Widgets
+WidgetData fields
+
+| Field | Default | Meaning |
+id, text | "" | identifier / label |
+x,y,width,height | 0,0,200,60 | geometry (2× scale) |
+bg_color, fg_color, frame_color | 0 | 0 = take from theme, else override |
+font_size | 0 | 0 = theme size, else per-widget |
+primary | false | accent-colored button |
+checked | false | checkbox / radio state |
+value, target_value | 0 | slider / progress (0..1) |
+items | [] | listbox / dropdown entries |
+picture | null | RawPicture for sprite / raw widgets |
+on_change / on_page_click / on_window_click | null | callbacks |
+
+Factory methods (on page or any container)
+p.Button(d); p.Label(d); p.Input(d); p.Checkbox(d); p.Radiobutton(d);
+p.Slider(d); p.Progressbar(d); p.Listbox(d); p.Dropdown(d);
+p.TreeView(d); p.TreeNode(d); p.ScrollView(d);
+p.RawPictureWidget(d); p.SpriteButton(d);
+Examples
+// accent button
+gui::WidgetData b; b.id="go"; b.text="Run"; b.primary=true;
+b.x=100; b.y=100; b.width=300; b.height=70;
+p.Button(b);
+
+// input field (click to focus, bottom line + blinking caret)
+gui::WidgetData i; i.id="name"; i.x=100; i.y=200; i.width=500; i.height=68;
+p.Input(i);
+
+// slider drives progress
+gui::WidgetData s; s.id="vol"; s.x=100; s.y=300; s.width=600; s.height=48; s.value=0.4f;
+p.Slider(s);
+gui::WidgetData pr; pr.id="prog"; pr.x=100; pr.y=380; pr.width=600; pr.height=44;
+p.Progressbar(pr);
+Nested containers
+auto& sv = p.ScrollView(d); // returns Widget&
+sv.Button(inner); // children live inside
+auto& tv = p.TreeView(d);
+auto& n1 = tv.TreeNode(n); // node
+n1.Label(child); // leaf inside node
+
+
+
+
+Themes & Customization
+Switch built-in themes
+gui::set_theme(gui::ThemeStyle::WIN11); // rounded, blue accent
+gui::set_theme(gui::ThemeStyle::TERMINAL); // square, green accent
+// hotkey F6 toggles at runtime (see demo)
+Theme struct (all tunable)
+struct Theme {
+ ThemeStyle style;
+ int radius, radius_sm, font_size; // 12/8/32 (win11), 0/0/32 (term)
+ uint32_t window_bg, panel_bg, text, text_dim;
+ uint32_t btn, btn_h, btn_p, border, border_h; // button + hover + press
+ uint32_t accent, accent_h, accent_p, on_accent;
+ uint32_t input_bg, focus;
+ uint32_t track, prog_bg;
+ uint32_t list_bg, list_h, list_sel, list_sel_text;
+ uint32_t tab_bg, tab_h, tab_active;
+};
+const Theme& theme(); // current
+Per-widget override (beats theme)
+gui::WidgetData d;
+d.bg_color = 0x332211; // non-zero overrides theme
+d.fg_color = 0xFFCC00;
+d.frame_color = 0x00FF88;
+d.font_size = 40; // per-widget size
+Rule: 0 = use theme. Any other value = your override. This is the C(override, theme) helper in widget.h.
+Where theme values live
+Edit libs/gui/core/theme.cpp — the two static structs t_win11 / t_term. Field order matches the struct above (e.g. the pair input_bg, focus is the 14th/15th value).
+
+
+
+
+Custom Widgets
+Three levels of extension, from easy to full.
+1. Restyle an existing widget (no code change)
+gui::WidgetData d;
+d.type = gui::WidgetType::BUTTON; // or set via factory
+d.bg_color = 0x402020; d.frame_color = 0xFF4444; d.font_size = 28;
+p.Button(d);
+2. Compose with RawPicture (sprite button)
+auto pic = std::make_shared<gui::RawPicture>(300, 100, 32);
+pic->clear(0x202020);
+pic->fillRoundRect(0,0,300,100,16,0x0078D4);
+pic->drawText(win.display(), 20, 30, "Custom", 0xFFFFFF, 1);
+gui::WidgetData d; d.picture = pic; d.width=300; d.height=100;
+p.SpriteButton(d); // still clickable, emits button.click
+3. Add a brand-new widget type
+
+widget.h: add enum value WidgetType::MY_WIDGET
+widget.h: add factory decl Widget& MyWidget(WidgetData);
+widget.cpp: implement factory (a.type = ...; return add_widget(...))
+- draw: add a case in
Widget::draw dispatch → your wdraw::my(...)
+- input: add a case in
Widget::handle_press (return 1 consumed / 2 capture)
+
+// widget.cpp factory
+Widget& combat::MyWidget(WidgetData a){ a.type=WidgetType::MY_WIDGET; return add_widget(std::move(a)); }
+
+// draw dispatch (Widget::draw)
+case WidgetType::MY_WIDGET: wdraw::my(d, win, gc, *this, ax, ay); break;
+
+// your renderer (any draw_*.cpp)
+void wdraw::my(Display* d, Drawable win, GC gc, const Widget& w, int ax, int ay) {
+ const auto& t = theme();
+ XSetForeground(d, gc, t.accent);
+ x_fill_round(d, win, gc, ax, ay, w.data.width, w.data.height, t.radius);
+ gui_text(d, win, gc, ax+12, gui_base_c(ay, w.data.height, t.font_size),
+ w.data.text, t.on_accent, t.font_size);
+}
+Declare your wdraw::my in widget.h and, if it needs protected widgets, add it as friend of combat (like basic/toggles/lists).
+
+
+
+
+Events
+EventBus
+int tok = gui::EventBus::get().on("button.click", [](const gui::EventData& e){ ... });
+gui::EventBus::get().off(tok);
+gui::EventBus::get().emit("my.event", {"id","text",0.5f,1,true});
+Built-in events
+
+| Event | Data |
+button.click | source_id, text |
+checkbox.change | source_id, flag |
+radio.change | source_id, flag=true |
+slider.change | source_id, value 0..1 |
+list.select | source_id, text, index |
+dropdown.select | source_id, text, index |
+tree.toggle | source_id, flag=expanded |
+input.submit | source_id, text (Enter) |
+page.open | source_id = page name |
+
+Per-widget callbacks (alternative)
+d.on_change = []{ ... }; // value/state changed
+d.on_page_click = [](gui::page& p){ ... }; // button clicked
+d.on_window_click= [](gui::window& w){ ... };
+Global logger (debug)
+gui::EventBus::get().set_global_logger([](const std::string& e, const gui::EventData& d){
+ std::cout << "[LOG] " << e << "\n";
+});
+
+
+
+
+Animations
+All animation state lives in struct Widget as 0..1 floats, advanced in Widget::tick(dt) and applied in Widget::draw().
+
+| Field | Drives | Where applied |
+hover_a | hover highlight | draw_basic / toggles color mix |
+press_a | press darkening | draw_basic color mix |
+push_a | push-down offset (6px) | Widget::draw: ay += ease(push_a)*6 |
+check_a | checkmark / radio dot reveal | draw_toggles |
+anim | dropdown open/close | draw_lists popup height |
+cursor_timer / cursor_visible | input caret blink (0.5s) | draw_basic |
+
+Tune speed
+// Widget::tick — the speed constants
+hover_a = approach(hover_a, hovered?1:0, dt, 10); // higher = snappier
+push_a = approach(push_a, pressed?1:0, dt, 18);
+check_a = approach(check_a, checked?1:0, dt, 10);
+Disable push-down (e.g. for slider)
+// Widget::draw
+int ay = data.y + oy + (data.type == WidgetType::SLIDER ? 0 : (int)(ease(push_a)*6));
+Remove color flicker (design rule)
+Colors fed into x_fill_round/x_draw_round/XDrawArc must NOT depend on animated hover_a/press_a. Keep animation in safe places: checkmark lines, radio dot, slider thumb position, push-down offset. This is why checkbox/radio use static border colors.
+
+
+
+
+Debug & Performance
+Hotkeys
+
+| Key | Action |
+| F1 | Debug overlay (FPS, widgets, partial updates, mouse, event log) |
+| F2 | Dirty-rect visualization (XOR flash of repainted regions) |
+| F3 | Click markers (red cross at click point) |
+| F4 | Widget bounds (magenta outlines) |
+| F5 | Console event logging |
+| F6 | Toggle theme WIN11 ↔ TERMINAL (via on_key) |
+
+Programmatic access
+win.debug().show_debug_overlay = true;
+win.debug().show_dirty_rects = true;
+win.debug().max_log_size = 30;
+std::cout << win.debug().fps << "\n";
+
+win.mark_dirty(x,y,w,h); // invalidate a region
+win.mark_all_dirty(); // full repaint
+Why it's fast
+
+- Dirty rectangles — only changed regions redraw;
Partial updates counter shows it
+- Only active page is ticked/rendered
+- Text cache — strings rendered once to 1-bit masks, drawn with one
XFillRectangle (no XGetImage)
+- Overlay throttle — debug panel refreshes at 10 Hz
+- Idle sleep —
usleep(10ms) when nothing is dirty → ~0% CPU at rest
+- Frame cap —
set_max_fps(), default 240
+
+F2 flashes only visualize user dirty rects (snapshot taken before flash/marker/overlay rects) — no feedback loop, FPS stays high.
+
+
+
+
+API Reference
+gui::window
+window(title) / ~window()
+update() running() display()
+addTAB_BUTTON(d) addPAGE(n) configur_page(n, fn, active) openPAGE(n)
+find(id) set_focus(w)
+set_font(p) set_font_size(px) set_icon(p|pic) set_default_icon() set_max_fps(n)
+debug() mark_dirty(x,y,w,h) mark_all_dirty()
+std::function<void(KeySym)> on_key;
+gui::combat (container base: page, Widget)
+Button/Label/Input/Checkbox/Radiobutton/Slider/Progressbar/
+Listbox/Dropdown/TreeView/TreeNode/ScrollView/RawPictureWidget/SpriteButton
+visit(fn) find(id) find_at(x,y) count_widgets()
+tick(dt) render_all(...) render_dirty(...) mark_all_dirty(...)
+process_press(...) process_wheel(...)
+gui::Widget
+WidgetData data;
+float hover_a, press_a, check_a, push_a, anim, phase;
+bool hovered, pressed, focused, cursor_visible, open_target;
+float cursor_timer;
+setValue(v) getValue()
+tick(dt) draw(...) draw_popup(...)
+handle_press/drag/release/wheel(...)
+contains(...) content_height() mark_dirty(...)
+gui::RawPicture
+create(w,h,bits) clear(c) setPixel/getPixel/blendPixel
+drawLine/drawRect/fillRect/fillRoundRect
+drawCircle/fillCircle/fillTriangle/fillPolygon
+drawText(dpy,x,y,t,c,scale) blit(src,dx,dy)
+load(path) // BMP 24/32, PPM P6
+present(dpy,win,gc,dx,dy)
+gui::FontManager
+FontManager::get()
+load(path) available() set_default_size(px) default_size()
+ascent/descent/line_height/text_width(size)
+draw(RawPicture&,...) draw(Display*,Drawable,GC,...)
+gui::EventBus / gui::DirtyRegion / gui::Theme
+EventBus::get().on/off/emit/set_global_logger
+DirtyRegion: add/mark_all/is_dirty/intersects/get/clear
+theme() set_theme(ThemeStyle)
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/screenshots/theme_win11.png b/docs/screenshots/theme_win11.png
new file mode 100644
index 0000000..dff15f0
Binary files /dev/null and b/docs/screenshots/theme_win11.png differ