Необычный интерфейс
Собрал для вас подборку редких, необычных и малоизвестных UI-библиотек — для построения интерфейсов в играх, на устройствах и десктопном ПО.
Статья была опубликована на Хабре.
Ликбез
Стоит задать на любом техническом форуме вполне невинный вопрос:
и разверзнутся бездны ада, треша, угара и содомии.
Из потока говен, исторгаемых на вас местными обитателями, с большим трудом и отвлекаясь на вопросы родословной, половой ориентации и политических пристрастий все участников дискуссии, узнаете что есть два стула основных варианта: QT и GTK.
И разумеется веб-интерфейс, который теперь пихают везде и для всего
Если вопрос был задан на форуме, посвященном Windows, то все будет еще печальнее и дальше стандартного WPF дело скорее всего не зайдет.
Ну может пара старых троллей вспомнят про «какой-то там» WinAPI и MFC.
Примерно тоже самое будет и у маководов, где вам посоветуют очевидное «используйте Swift», также поступят и оставшиеся на свете любители Delphi, рассказав что «UI это Delphi», а все остальное от лукавого.
Не то чтобы все советчики были откровенными п#дорасами на зарплате у больших корпораций, которые собственно и стоят за ключевыми технологиями, просто люди в основной своей массе тупы и ленивы.
Поэтому большинство из виденных автором за свою долгую жизнь разработчиков вообще не смогли бы представить, что может быть и по-другому:
«эти #бучие кнопки» запросто может рисовать программулинка на пару тысяч строк кода и не требующая пары лет на свое изучение.
Именно такие удивительные проекты я вам сейчас и покажу.
Тестовая среда
В качестве тестовой среды в этот раз выступал Debian Linux 12, а сборка и запуск специально производились на очень слабом и устаревшем ноутбуке — в качестве демонстрации производительности.
Большая часть из приведенных ниже библиотек и фреймворков — кроссплатформенные и поддерживают все основные типы пользовательского окружения: Linux, Windows, Mac.
А с учетом небольших размеров — вопрос портирования вообще врядли может стоять.
Nuklear
https://github.com/Immediate-Mode-UI/Nuklear/tree/master
Скриншоты из реальных проектов, использующих эту библиотеку можно созерцать на заглавной картинке к статье.
A single-header ANSI C immediate mode cross-platform GUI library
18к строк кода на C, что очень неплохо для такого функционала.
Авторы не врут и по поводу «single-header», но есть нюанс:
разработка ведется в разных исходных файлах, которые затем «упаковываются» в один большой экспортируемый заголовок nuklear.h
Осторожно, по ссылке выше заголовочный .h файл размером больше 1 Мб — может подвесить браузер при открытии.
It was designed as a simple embeddable user interface for application and does not have any dependencies, a default render backend or OS window/input handling but instead provides a highly modular, library-based approach
Думаю очевидно, что при таком подходе часть необходимого для работы функционала пересаживается с шеи автора библиотеки на вашу собственную — речь в первую очередь про те самые «графические бекэнды».
все что вам явно не надо в проект добавлено не будет.
все что вы явно не добавите — в проекте не появится.
Таким образом даже классический «fallback mode» — откат на X11-бекэнд при отсутствии поддержки 3D-ускорения немедленно превращается в гемморой космического масштаба.
Пример использования (без заголовков):
/* init gui state */ struct nk_context ctx; nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font); enum {EASY, HARD}; static int op = EASY; static float value = 0.6f; static int i = 20; if (nk_begin(&ctx, "Show", nk_rect(50, 50, 220, 220), NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) { /* fixed widget pixel width */ nk_layout_row_static(&ctx, 30, 80, 1); if (nk_button_label(&ctx, "button")) { /* event handling */ } /* fixed widget window ratio width */ nk_layout_row_dynamic(&ctx, 30, 2); if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY; if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD; /* custom widget pixel width */ nk_layout_row_begin(&ctx, NK_STATIC, 30, 2); { nk_layout_row_push(&ctx, 50); nk_label(&ctx, "Volume:", NK_TEXT_LEFT); nk_layout_row_push(&ctx, 110); nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f); } nk_layout_row_end(&ctx); } nk_end(&ctx);
Вот так выглядит его showcase на Linux с X11-бекэндом в действии:
Демо-проекты собираются как под Windows так и под Linux.
К сожалению везде используется самопальная сборка и «упаковка» с помощью скрипта на Python — все это придется подкручивать, поскольку по-умолчанию точно не соберется.
Что касается реального применения, автору не удалось найти никаких пруфов использования Nuklear для игр серии Call of Duty, откуда был взят данный замечательный скриншот:
Так что оставим этот референс на совести автора библиотеки.
Следующий проект, авторы которого серьезно угорели по эффектам и сложным переключателям:
Elements C++ GUI library
https://github.com/cycfi/elements
Этот замечательный проект куда более продвинут в технологическом плане:
Elements is a lightweight, fine-grained, resolution-independent, extremely modular GUI library. The library is written using modern C++20 language features
Аж на C++20, еще и со специализированным DSL для описания интерфейсов:
It has a declarative interface with a sensible and easy-to-use Domain Specific Embedded Languages (DSEL) syntax for constructing the GUI elements. A declarative description of the GUI is written exclusively in C++, and therefore, there is no need for an external visual GUI editor or code generator.
Вот так выглядит исходный код «Hello word» с использованием этой библиотеки:
#include <elements.hpp> using namespace cycfi::elements; int main(int argc, char* argv[]) { app _app("Hello Universe"); window _win(_app.name()); _win.on_close = [&_app]() { _app.stop(); }; view view_(_win); view_.content( scroller(image{"space.jpg"}) ); _app.run(); return 0; }
Стоит отметить что фреймворк использует немаленькую библиотеку Cairo и еще кучу внешних зависимостей:
Так что сборка достаточно сложная, зато официально поддерживается сборка для Windows, MacOS и Linux.
Демонстрация нескольких тестовых приложений в работе на Linux:
GUILite.h
https://github.com/idea4good/GuiLite
Следующий интересный проект (7.5к звезд), описываемый автором как:
The smallest header-only GUI library (4 KLOC) for all platforms.
интересен в первую очередь набором поддерживаемых платформ:
Да, эта штука создана для использования на устройствах:
В работе в качестве десктоп-приложения на Linux:
Вся библиотека находится в единственном заголовке, примеры вынесены в отдельный репозиторий.
Думаю не стоит упоминать, что из-за такой миниатюризации и универсальности, существенная часть логики вынесена в конкретные реализации, поэтому примеры имеют конские размеры и сложную сборку:
MicroUI
https://github.com/rxi/microui
Еще один отличный проект (3.8к звезд не дадут соврать), который стоит взять на заметку:
A tiny, portable, immediate-mode UI library written in ANSI C
Действительно «tiny», поскольку вся реализация занимает ~ 1.1к строк на С (два файла), а единственная зависимость — SDL2:
CFLAGS="-I../src -Wall -std=c11 -pedantic `sdl2-config --libs` $GLFLAG -lm -O3 -g" gcc main.c renderer.c ../src/microui.c $CFLAGS
Showcase доступен для просмотра и в браузере:
Пример использования (без заголовков):
if (mu_begin_window(ctx, "My Window", mu_rect(10, 10, 140, 86))) { mu_layout_row(ctx, 2, (int[]) { 60, -1 }, 0); mu_label(ctx, "First:"); if (mu_button(ctx, "Button1")) { printf("Button1 pressed\n"); } mu_label(ctx, "Second:"); if (mu_button(ctx, "Button2")) { mu_open_popup(ctx, "My Popup"); } if (mu_begin_popup(ctx, "My Popup")) { mu_label(ctx, "Hello world!"); mu_end_popup(ctx); } mu_end_window(ctx); }
Есть даже детальная документация.
Очень интересная штука, рекомендую.
Alia
https://github.com/alialib/alia
Следующий интересный проект, скромно описываемый как:
a declarative UI library for C++
выносит мозг неподготовленным пользователям одной фразой:
alia currently targets the web.
Это на моей памяти первый и единственный UI-фреймворк на C++, официальное целевое использование для которого — веб.
Несмотря на заявленную поддержку Linux, сборка для него оказалась сломана, так что собрать удалось только из-под Windows 11.
В качестве движка для отрисовки, используется известная библиотека Skia, которую например использует ваш любимый Chrome.
Так выглядит showcase:
Так выглядит исходный код «Hello, world»:
void greeting_ui(html::context ctx, duplex<std::string> name) { html::p(ctx, "What's your name?"); // Allow the user to input their name. html::input(ctx, name); // If we have a name, greet the user. alia_if(name != "") { html::p(ctx, "Hello, " + name + "!"); } alia_end }
В живую его можно посмотреть на сайте проекта.
Clay
https://github.com/nicbarker/clay
Проект — не совсем полноценный UI-фреймворк, но тоже достоин внимания:
Clay (short for C Layout) is a high performance 2D UI layout library.
Перечислю ключевые фичи, по мере чтения которых будет нарастать ох#евание:
- Single ~2k LOC clay.h file with zero dependencies (including no standard library)
- Wasm support: compile with clang to a 15kb uncompressed .wasm file for use in the browser
- Static arena based memory use with no malloc / free, and low total memory overhead (e.g. ~3.5mb for 8192 layout elements).
- React-like nested declarative syntax
Официальный сайт проекта тоже реализован с помощью этой библиотеки:
Т.е. сайт фактически написан на С. Целиком, включая интерактив.
И собирается с помощью cmake, да.
Думаю вам также будет интересно увидеть как выглядит код на С в декларативном стиле:
// Parent element with 8px of padding CLAY({ .layout = { .padding = CLAY_PADDING_ALL(8) } }) { // Child element 1 CLAY_TEXT(CLAY_STRING("Hello World"), CLAY_TEXT_CONFIG({ .fontSize = 16 })); // Child element 2 with red background CLAY({ .backgroundColor = COLOR_RED }) { // etc } }
Несмотря на всю шизоидность, библиотеку реально используют, так выглядит один из реальных проектов:
К сожалению доступные примеры от автора сильно проще, так например выглядит showcase, собранный в качестве desktop-приложения:
ImGui
https://github.com/ocornut/imgui
Достаточно известный проект (не у нас), собравший 64к звезд на Github:
Bloat-free Graphical User interface for C++ with minimal dependencies
реализует наверное самый продвинутый интерфейс за пределами известных UI-фреймворков, при этом оставаясь в минимальных размерах.
Исходный код для демо выше выглядит следующим образом:
// Create a window called "My First Tool", with a menu bar. ImGui::Begin("My First Tool", &my_tool_active, ImGuiWindowFlags_MenuBar); if (ImGui::BeginMenuBar()) { if (ImGui::BeginMenu("File")) { if (ImGui::MenuItem("Open..", "Ctrl+O")) { /* Do stuff */ } if (ImGui::MenuItem("Save", "Ctrl+S")) { /* Do stuff */ } if (ImGui::MenuItem("Close", "Ctrl+W")) { my_tool_active = false; } ImGui::EndMenu(); } ImGui::EndMenuBar(); } // Edit a color stored as 4 floats ImGui::ColorEdit4("Color", my_color); // Generate samples and plot them float samples[100]; for (int n = 0; n < 100; n++) samples[n] = sinf(n * 0.2f + ImGui::GetTime() * 1.5f); ImGui::PlotLines("Samples", samples, 100); // Display contents in a scrolling region ImGui::TextColored(ImVec4(1,1,0,1), "Important Stuff"); ImGui::BeginChild("Scrolling"); for (int n = 0; n < 50; n++) ImGui::Text("%04d: Some text", n); ImGui::EndChild(); ImGui::End();
Одними только официально поддерживаемыми биндингами закрывается вопрос поддержки всех основных конфигураций:
- Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, SDL_GPU, SDL_Renderer2/3, Vulkan, WebGPU.
- Platforms: GLFW, SDL2/SDL3, Win32, Glut, OSX, Android.
- Frameworks: Allegro5, Emscripten.
А есть еще и сторонние, поддерживаемые внешними разработчиками.
Скриншот одного из реальных проектов:
Список проектов, в котором используется данная библиотека внушает ужас уважение.
Полный showcase в работе на Linux:
Всячески рекомендую к использованию.
ATG
https://github.com/ec429/libatg/tree/master
Следующий интересный проект на тему кастомного интерфейса называется atg:
atg is a small, simple GUI library/toolkit for SDL, providing things like buttons and clickables to allow you to concentrate on your program logic. atg is loosely based on Spiffy's GUI, though genericised.
Написан на чистом С, отрисовка осуществляется с помощью библиотеки SDL, она же является единственной зависимостью.
Объем исходного кода — ~2.5к строк.
Собирается на любой ОС с поддержкой SDL, также есть готовый Makefile для Windows (с использованием mingw).
libUI
https://github.com/andlabs/libui
Достаточно известная библиотека, собравшая 10.8к звезд на Github:
Simple and portable (but not inflexible) GUI library in C that uses the native GUI technologies of each platform it supports.
Разработка ведется с 2016 года, написана на чистом С (основная часть), имеет кучу биндингов для разных языков и целых два полноценных форка, причем один форкнут из другого.
Поддерживаются все основные ОС:
- Windows: Windows Vista SP2 with Platform Update or newer
- Unix: GTK+ 3.10 or newer
- Mac OS X: OS X 10.8 or newer
Собирается с помощью новомодных meson и ninja.
Использует «низший слой» для кроссплатформенности, поэтому интерфейс внешне адаптируется под системный.
И наконец так выглядит showcase в моем Debian Linux:
Hikogui
https://github.com/hikogui/hikogui
A portable, low latency, retained-mode GUI framework written in C++
целиком ориентирован на современный Windows-десктоп с 3D-ускорением:
Официально поддерживается только Windows:
Несмотря на заявленную поддержку gcc и Linux, на данный момент собирается и работает только на Windows.
Пример исходного кода с использованием этой библиотеки:
int hi_main(int argc, char *argv[]) { observer<int> value = 0; auto gui = hi::gui_system::make_unique(); auto &window = gui.make_window(txt("Radio button example")); window.content().emplace<label_widget>("A1", txt("radio buttons:")); window.content().emplace<radio_button_widget>("B1", txt("one"), value, 1); window.content().emplace<radio_button_widget>("B2", txt("two"), value, 2); window.content().emplace<radio_button_widget>("B3", txt("three"), value, 3); return gui->loop(); }
Демонстрация в работе одного из реальных приложений, использующих эту библиотеку:
Visage
https://github.com/VitalAudio/visage
Наконец последний на сегодня, но точно не последний в плане интересности проект:
Visage is a GPU-accelerated, cross-platform C++ library for native UI and 2D graphics. It merges the structure of a UI framework with the features of a creative graphics libraries.
Ориентирован в первую очередь на спецэффекты и 3D, но в отличие от предыдущего проекта, честно поддерживает все основные платформы:
Демо в работе на Linux и Vulkan:
Редактор шейдеров, использующий эту библиотеку:
Пример исходного кода:
#include <visage_app/application_window.h> int main() { visage::ApplicationWindow app; app.onDraw() = [&app](visage::Canvas& canvas) { canvas.setColor(0xffff00ff); canvas.fill(0, 0, app.width(), app.height()); }; app.show(800, 600); // Opens as 800 x 600 pixel window app.runEventLoop(); // Runs window events. Returns when window is closed. return 0; }