Необычный интерфейс

от автора

Собрал для вас подборку редких, необычных и малоизвестных UI-библиотек — для построения интерфейсов в играх, на устройствах и десктопном ПО.

Ликбез

Стоит задать на любом техническом форуме вполне невинный вопрос:

какую UI-библиотеку/фреймворк выбрать для нового проекта?

и разверзнутся натурально бездны ада.

Из потока исторгаемых говен, с большим трудом и отвлекаясь на ненужные вопросы родословной, половой ориентации и политических пристрастий все участников дискуссии, вы узнаете что есть два стула основных варианта: QT и GTK.

И разумеется веб-интерфейс, который теперь используют для любых задач.

Если вопрос был задан на форуме, посвященном Windows — все будет еще печальнее и дальше стандартного WPF дело скорее всего не зайдет. Ну может пара опытных пользователей еще вспомнят про «какой-то там» WinAPI или MFC.

Примерно тоже самое будет у любителей Mac, где вам посоветуют очевидное «используйте Swift», также поступят и оставшиеся на свете пользователи Delphi, рассказав что «UI это Delphi», а все остальное — от лукавого.

Не то чтобы все советующие были на зарплате у больших корпораций, которые и стоят за ключевыми технологиями, просто люди в основной своей массе не очень любознательны.

Поэтому большинство разработчиков просто не могут представить, что кнопки и формы может рисовать крошечная библиотека на 2к строк кода, не требующая пары лет на свое изучение.

Именно такие удивительные проекты я вам сейчас и покажу.

Тестовая среда

В качестве тестовой среды в этот раз выступал Debian Linux 12, сборка и запуск специально производились на очень слабом и устаревшем ноутбуке — в качестве демонстрации производительности.

Также несколько проектов с Windows-спецификой были собраны и запущены на Windows 11.

Большая часть из приведенных ниже библиотек и фреймворков — кроссплатформенные и поддерживают все основные типы пользовательского окружения: 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 и еще несколько внешних зависимостей:

pkg-config, fontconfig, freetype2, bzip2, expat, zlib, libpng, libwebp

Так что сборка достаточно сложная, зато вполне официально поддерживается Windows, MacOS и Linux.

Демонстрация нескольких тестовых приложений в работе на Linux:

GUILite.h

https://github.com/idea4good/GuiLite

Следующий проект (7.5к звезд), описываемый автором как:

The smallest header-only GUI library (4 KLOC) for all platforms.

интересен в первую очередь набором поддерживаемых платформ:

iOS/macOS/WatchOS, Android, Linux, Windows, RTOS… or MCU without OS

Да, библиотека создана в первую очередь для использования на «голом железе»:

В работе в качестве десктоп-приложения на 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); }

Есть даже детальная документация.

В действии на Linux выглядит впечатляюще:

Очень интересная штука, рекомендую.

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», собранный в качестве приложения на Windows:

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.

Использует «низший слой» для кроссплатформенности, поэтому интерфейс внешне адаптируется под системный.

Так это выглядит в Windows:

В MacOS:

И наконец так выглядит «showcase» в моем Debian Linux:

Тест работы со шрифтами:

Hikogui

https://github.com/hikogui/hikogui

Следующий интересный проект:

A portable, low latency, retained-mode GUI framework written in C++

целиком ориентирован на современный Windows-десктоп с 3D-ускорением:

Официально поддерживается только Windows:

  • MSVC — Windows 10 (or newer) — x64

Пример исходного кода с использованием этой библиотеки:

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, но в отличие от предыдущего проекта, честно поддерживает все основные платформы:

  • Windows: Direct3D11

  • MacOS: Metal

  • Linux: Vulkan

  • Web/Emscripten: WebGL

Демо в работе на Linux, с использованием Vulkan SDK:

Редактор шейдеров, использующий эту библиотеку:

Пример исходного кода:

#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; }

Эпилог

Очень надеюсь, что после этой подборки хоть кто‑то перестанет рассказывать несмешные шутки про «два стула» Gtk и Qt и поймет, что выбор вариантов для построения пользовательского интерфейса несколько шире и богаче.

Ну а если планируете свой проект, думаю подборка окажется полезной и что‑то из описанного выше вам точно подойдет — не надо сразу тащить внутрь гробовую плиту с надписью «Qt», поработайте хотя-бы на стадии прототипа в свое удовольствие.

Оригинал статьи как обычно в нашем блоге.


ссылка на оригинал статьи https://habr.com/ru/articles/894442/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *