9 января в 17:50

Nuklear — идеальный GUI для микро-проектов?

Nuklear — это библиотека для создания immediate mode пользовательских интерфейсов. Библиотека не имеет никаких зависимостей (только C89! только хардкор!), но и не умеет создавать окна операционной системы или выполнять реальный рендеринг. Nuklear — встраиваемая библиотека, которая предоставляет удобные интерфейсы для отрисовки средствами реализованного приложения. Есть примеры на WinAPI, X11, SDL, Allegro, GLFW, OpenGL, DirectX. Родителем концепции была библиотека ImGUI.


Чем прекрасна именно Nuklear? Она имеет небольшой размер (порядка 15 тысяч строк кода), полностью содержится в одном заголовочном файле, создавалась с упором на портативность и простоту использования. Лицензия Public Domain.


Веб-демо Nuklear


Постановка задачи


У меня часто возникают задачи, для реализации которых приходится писать мелкие утилитки в несколько сотен строк кода. Обычно в результате получается консольное приложение, которое кроме меня никто толком использовать не может. Возможно, простой GUI сможет сделать эти утилиты более удобными?


Итак, требования к результату:


  1. Малый размер, до сотен килобайт.
  2. Кроссплатформенность, для начала хотя бы Windows и Linux.
  3. Отсутствие зависимости от внешних библиотек в Windows, всё должно быть в одном EXE-файле.
  4. Приличный/красивый внешний вид.
  5. Поддержка картинок в форматах JPG и PNG.
  6. Простота разработки, возможность разработки в Windows и Linux.
    Справится ли Nuklear?

Nuklear NodeEdit


Для примера рассмотрим создание утилиты dxBin2h (GitHub) — она считывает файл побайтово и записывает в виде Си-массива. Кроме основного функционала программа имеет всякие "плюшки", типа удаления ненужных символов и т.п. Обычно ради стороннего функционала и создаются свои маленькие утилиты. Например, dxBin2h создавалась для Winter Novel, для предварительной обработки ASCII-файлов.


Простота разработки, кроссплатформенность


Уж с чем, а с простотой разработки проблем быть не должно. Ведь с прицелом на неё библиотека и создавалась, так? Прямо в Readme на GitHub есть пример. Абсолютно понятные и лаконичные 20 строк кода дают красивый и чёткий результат.


Код примера
/* init gui state */
struct nk_context ctx;
nk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);

enum {EASY, HARD};
int op = EASY;
float value = 0.6f;
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);

Но не всё так просто. Часть, отвечающая непосредственно за просчёт GUI действительно проста. Только должен быть ещё и рендер. Идём в папку demo, выбираем понравившийся. И видим уже далеко не 20 строк. Мало того, хотя примеры и рисуют на экране примерно одинаковый результат, но код значительно отличается именно из-за рендера.


Пример инициализации на WinAPI и SDL

WinAPI:


static LRESULT CALLBACK
WindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    switch (msg) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    if (nk_gdip_handle_event(wnd, msg, wparam, lparam))
        return 0;
    return DefWindowProcW(wnd, msg, wparam, lparam);
}

int main(void)
{
    GdipFont* font;
    struct nk_context *ctx;

    WNDCLASSW wc;
    RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };
    DWORD style = WS_OVERLAPPEDWINDOW;
    DWORD exstyle = WS_EX_APPWINDOW;
    HWND wnd;
    int running = 1;
    int needs_refresh = 1;

    /* Win32 */
    memset(&wc, 0, sizeof(wc));
    wc.lpfnWndProc = WindowProc;
    wc.hInstance = GetModuleHandleW(0);
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszClassName = L"NuklearWindowClass";
    RegisterClassW(&wc);

    AdjustWindowRectEx(&rect, style, FALSE, exstyle);

    wnd = CreateWindowExW(exstyle, wc.lpszClassName, L"Nuklear Demo",
        style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,
        rect.right - rect.left, rect.bottom - rect.top,
        NULL, NULL, wc.hInstance, NULL);

SDL:


int
main(int argc, char* argv[])
{
    /* Platform */
    SDL_Window *win;
    SDL_GLContext glContext;
    struct nk_color background;
    int win_width, win_height;
    int running = 1;

    /* GUI */
    struct nk_context *ctx;

    /* SDL setup */
    SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, "0");
    SDL_Init(SDL_INIT_VIDEO);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
    win = SDL_CreateWindow("Demo",
        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
        WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI);
    glContext = SDL_GL_CreateContext(win);
    SDL_GetWindowSize(win, &win_width, &win_height);

Отсутствие зависимостей в Windows


Ну хорошо, берём рендером SDL2 с OpenGL и получаем результирующее приложение под Windows, Linux, Mac OS X, Android, iOS и ещё кучу чего! Всё супер, только вот в стандартной поставке Windows библиотеки SDL нет. Значит, придётся тащить с собой. А это нарушает первое требование (малый размер), т.к. сама SDL весит порядка мегабайта.


Зато в списке примеров виднеется GDI+, которая есть в Windows начиная с XP. GDI+ умеет ttf-шрифты, картинки PNG и JPG, и всё это возможно загружать прямо из памяти. Пускай в итоге будет 2 возможных рендера: GDI+ для Windows и SDL для всех остальных случаев. Можно вынести часть кода, зависящую от рендера, в отдельный Си-файл (nuklear_cross.c). Тогда основной код не будет перегружен, и можно будет сфокусироваться именно на интерфейсе, что значительно упрощает разработку. Дополнительным плюсом получаем ускорение компиляции — весь Nuklear будет компилироваться в отдельный объектный файл, который будет редко изменяться.


Windows, отрисовка через GDI+, шрифт Arial 12pt:


dxBin2h GDI+ Arial 12pt


Linux, отрисовка через SDL2 и OpenGL, шрифт по умолчанию:


dxBin2h SDL2 linux stdfont


Приложение выглядит совсем по-разному! И первое, что бросается в глаза — шрифт.


Шрифт


Чтобы приложение выглядело одинаково во всех операционных системах нужно использовать один и тот же шрифт. Можно было бы взять какой-нибудь системный шрифт, который гарантированно есть везде. Но такого шрифта нет. Поэтому шрифт придётся включать в своё приложение. ttf-шрифты обычно весят сотни килобайт, но из них хорошо создаются подмножества с необходимыми символами. Например, с помощью веб-сервиса FontSquirrel. DejaVu Serif ужался до 40kb, хотя и содержит в себе кириллицу, польский и ещё кучу языков.


Всё было бы отлично, но GDI+ драйвер для Nuklear не умел загружать шрифт из памяти, только из файла. Пришлось исправлять… Кстати, шрифт можно включить в своё приложение с помощью той же dxBin2h.


Windows, DejaVu Serif:


dxBin2h Windows  DejaVu Serif


Linux, DejaVu Serif:


dxBin2h Linux DejaVu Serif


Уже намного лучше. Но мне не нравится внешний вид чекбоксов. И хотелось бы увидеть картинки.


Картинки: PNG, JPG


И SDL2 и GDI+ умеют загружать картинки. Но для SDL при загрузке JPG и PNG появляется дополнительная зависимость — SDL_image. Избавиться от неё довольно просто: используем stb_image.h, если проект собирается с SDL.


С GDI+ тоже не всё было хорошо. А именно, GDI+ драйвер для Nuklear не умел отрисовывать изображения средствами GDI+. Пришлось вникать в работу с изображениями и реализовывать самому (Pull Request). Теперь всё исправлено и код в официальном репозитории.


Код загрузки изображения через stb_image для OpenGL
struct nk_image dxNkLoadImageFromMem(const void* buf, int bufSize){
        int x,y,n;
        GLuint tex;
        unsigned char *data = stbi_load_from_memory(buf, bufSize, &x, &y, &n, 0);
        glGenTextures(1, &tex);
        glBindTexture(GL_TEXTURE_2D, tex);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
        return nk_image_id((int)tex);
}

Внешний вид приложения


Чтобы изменить вид чекбоксов в Nuklear есть механизм выставления стилей. Здесь включенный и выключенный чекбокс являются отдельными PNG-картинками. В этом же коде же выставляется красная тема из примеров Nuklear (файл style.c):


    nk_image checked = dxNkLoadImageFromMem( (void*)checked_image, sizeof(checked_image) );
    nk_image unchecked = dxNkLoadImageFromMem( (void*)unchecked_image, sizeof(unchecked_image) );

    set_style(ctx, THEME_RED);
    {struct nk_style_toggle *toggle;
        toggle = &ctx->style.checkbox;
        toggle->border = -2; /* cursor must overlap original image */
        toggle->normal          = nk_style_item_image(unchecked);
        toggle->hover           = nk_style_item_image(unchecked);
        toggle->active          = nk_style_item_image(unchecked);
        toggle->cursor_normal   = nk_style_item_image(checked);
        toggle->cursor_hover    = nk_style_item_image(checked);
    }

Приложение в Windows выглядит так:


dxBin2h Windows


В Linux:


dxBin2h Linux


Что в итоге?


  1. Windows EXE после компиляции 200kb, после ужатия UPX 90kb. В Linux из-за использования stb_image размер приложения в среднем на 100kb больше.
  2. Проверена работа в Windows и Linux.
  3. Шрифт и картинки хранятся как массивы в памяти приложения. Зависимостей не от WinAPI в Windows нет.
  4. Движок изменения стиля приложения работает.
  5. PNG и JPG загружаются средствами GDI+ и stb_image.
  6. Весь "грязный" платформенно-зависимый код вынесен в отдельный файл. Разработчик фокусируется именно на создании приложения.

Известные проблемы


  • Различное сглаживание шрифтов в разных операционных системах
  • Разный размер чекбоксов
  • Разная поддержка изображений (при использовании stb_image нужно избегать проблемных изображений)
  • Не полная поддержка юникода при урезанном шрифте
  • Нет примера на технологиях Mac OS X

Как пользоваться наработками


  1. Склонировать репозиторий https://github.com/DeXP/dxBin2h
  2. Скопировать оттуда папку "GUI" в свой проект
  3. Подключить "GUI/nuklear_cross.h", использовать функции оттуда
  4. При необходимости обновления файлов Nuklear скопировать их из официального репозитория поверх текущих.

Заключение


Приложение выглядит немного по-разному в разных операционных системах. Однако отличия незначительны, полученный результат меня удовлетворил. Nuklear не входит в категорию "я уверен, что будет работать везде и без тестирования". Зато входит в категорию "если что будет нужно — легко допишу".


Полезные ссылки



UPD: Добавил веб-демо, теперь на библиотеку можно посмотреть вживую онлайн.

Храбров Дмитрий @DeXPeriX
карма
48,5
рейтинг 40,9
Пользователь
Самое читаемое Разработка

Комментарии (69)

  • +2
    Вспоминается FLTK
    • +1

      FLTK написан на С++, а не на Си. Соответственно, будет занимать значительно больше места (примерно +200kb за stdlibc++). Лицензия у него LGPL, а не Public Domain. Но лично меня оттолкнул внешний вид.
      А вообще я бы хотел Qt, но в 100kb :-)

      • +2
        Благодаря си его еще можно например скриптовать tcc. Я его использую в мини аля-флеш плеере, у которого рантайм около 300кб (размер apk увеличивается на 100кб). Причем работает оно на десктопе, телефонах и веб через emscripten. Вот пример nanovg демки, обернутой в эту штуку (специальо для nuklear демки еще не делал).
        • 0

          Nanovg демка выглядит красиво. Есть ли такая же шкура, но натянутая на FLTK?
          Прикольно. Получается, что за счёт emscripten к списку поддерживаемых Nuklear платформ можно добавить и браузеры?

          • 0
            Это псевдо-интерфейс вручную нарисованный nanovg (это почти то же что html5 canvas api, возможности те же). В принципе если код демки использовать — натянуть можно много куда, самому nanovg ничего кроме gl\gles не надо.
            Насчет nuklear — да, собственно это уже делали, правда веб демка жаль уже 404, но я видел как она работала)
          • 0
            так точно. Nuklear поддерживает glfw и sdl, а это означает, что с emscripten проблем не будет. я сам увлекаюсь этой технологией, прям магия с --> llvm --> js
            • +1

              Ну, судя по комменту выше, проблемки всё-таки есть) И с SDL тоже, но они в процессе решения.
              С другой стороны практической ценности всё-равно вижу мало. У меня утилиты почти всегда файловые, а с этим насколько я в курсе у JavaScript проблемы.

              • 0
                насчет sdl не знаю для меня он слишком громоздкий в разрезе emscripten. А вот пример работы с glfw3, все там отлично рабоатет, как пример моя демка http://casualgum.com/test/mun.html
                зачем это? ну все та же мутиплатформенность, например ты сделал тулзовину или приложение, а в веб версии ее демо-версия… навскид идейка
                • 0

                  Ну у меня уже есть 2 мелкие тулзовины: одна конвертирует файл из одного 3D-формата в другой, а другая по файлу создаёт Си-массив. И той и той нужно читать файлы с диска. И вроде бы emscripten никак не может дать читать файлы с диска пользователя. Это была бы серьёзная дыра в безопасности.
                  А всякие тулзы типа "нарисуй градиент у нас онлайн и сохрани его как PNG" вроде проще сразу под веб и писать. Они ж будут под это заточены...

                  • 0
                    https://kripken.github.io/emscripten-site/docs/getting_started/Tutorial.html, раздел «Using files» (fopen)
                    • 0

                      C сервера — да. С компьютера пользователя никак. Но идея ясна. Так действительно можно делать демки. Хотя бы только со своим ограниченным набором файлов.

              • +1
                Через glfw там были какие то минорные проблемы, но в целом все хорошо работало. Собственно из скрипта аля-флеш мультика моего он тоже работает подо всеми платформами винда\линукс\мак\андройд\ios\веб.
                • 0

                  Так используется именно Nuklear? А какая библиотека была выбрана драйвером, SDL/glfw?

                  • 0
                    В демо что я кинул — только nanovg, но вообще да, в невыложенных «флешках» я использую и nuklear для интерфейса\кнопочек итд. Использую glfw, но это кухня плеера, для скрипта вшитого во «флешку», эти подробности скрыты.
                    • 0

                      Очень интересно! Были ли какие-то проблемы с переносом именно в веб? Как много времени было потрачено на решение?

                      • +1
                        Были, мне пришлось пропатчить emscripten, добавив loadDynamicLibrarySrc для загрузки скрипта из памяти. Т.к. скрипт грузится не из файла, а распаковывается из zip («флешка» это скрипт+ресурсы). Там еще по мелочи #ifdef EMSCRIPTEN, немного js в html чтобы загрузить флешку по линку в контейнер откуда emscripten файлы берет.
                        В целом ничего сложного, за выходные помоему уложился
                        • +1

                          Спасибо за идею, помощь и подсказки. Для примера собрал свою веб-демку Nuklear:
                          https://dexp.github.io/nuklear-webdemo/
                          Уже добавлена в публикацию.

                          • 0
                            Всегда пожалуйста)
      • +1
        Зато развивается он с 98 года:
        • 0

          Старое не всегда значит хорошее. Мне нравится примеры кода FLTK. Код красивый и лаконичный. По сути претензия к FLTK у меня только одна — ужасный и устаревший внешний вид. Если FLTK имеет хорошую кроссплатформенную поддержку скинов, то я готов пересмотреть своё решение. Иначе увольте. Такие интерфейсы делать в 2017 году считаю моветоном.

          • +1
            Посмотрел скриншоты у FLTK. На мой взгляд, примеры в статье выглядят не менее ужасно с точки зрения внешнего вида.
            • 0

              Возможно. Только вот поддержка скинов в Nuklear полноценна (пруф. на гитхабе, нижние скрины красивее).

  • 0
    Получается можно её использовать во встраиваемых системах на чистом железе, на микроконтроллерах?
    • 0
      Угу, только рендер свой написать.
      • 0
        Миленько :3
        Просто сейчас тоже разрабатываю библиотеку ГУЯ, но ориентируюсь только на МК.
        • 0
          Для рисования на совсем слабых контроллеров могу свою либу посоветовать: https://github.com/errorcalc/ESLowGraphicsLibrary
          • 0
            Пасибки, возможн когда-нибудь и воспользуюсь. Но сейчас я пишу хай лэвел либу, возможно, с менеджером окон. Аля emWin, только в разы более простую и открытую.
      • 0

        Да, именно так: можно использовать хоть на микроволновке, только нужно будет описать драйвер для рендеринга. И это будет намного проще, чем сделать библиотеку для GUI. Рендер — это буквально пара десятков функций типа: нарисуй прямоугольник, линию, круг, текст, картинку. А Nuklear сама уже на этой базе построит элементы GUI. Библиотека Nuklear занимает порядка 15 000 строк кода, GDI+ драйвер для неё — 1 000, SDL — 300.

        • 0
          Только обычно библиотеку для GUI на микроконтроллер не нужно делать такой. Там нет мыши (ну можно конечно втулить), и окон, и даже тач редко используется. Обычно пара кнопок и тогда требования к UI совершенно другие. И библиотека рендера часто тоже есть. Остается только воплощать идею заказчика. И 100кб там это сильно больше 16Мб Qt приложения на декстопе.

          Хотя конечно все бесспорно интересно как для PC так и для микроконтроллеров.
          • 0

            Размер уменьшится, если не тащить с собой ttf-шрифт или сильно его урезать. В Readme написано, что можно отказаться даже от stdlib. Наверное, это как раз для каких-нибудь микроконтроллеров и может быть полезно. Только да, интерфейс всё-таки ориентирован на десктопы/мобильники. Ну или как минимум относительно большой экран. Хотя опять же, может быть кто-нибудь попробует, расскажет и поделится своими впечатлениями.

  • +1
    Скриншот
    image
    напомнил еще одну GUI библиотеку — GWEN (GWork).
    Тоже поддерживаются различные рендереры: GDI, SFML, OpengGL, DirectX, Allegro. Правда она потяжелее и написана на C++
  • 0
    мне проект понравился, думаю может утащу к себе, я какраз люблю когда никаких зависимостей
    код смотрел, вижу что редактора нет, но может где-то существует и редактор под все это?
    • 0

      Визуального редактора форм под это дело точно нет. Не того масштаба проект. Такие визуальные редакторы нужны в основном для создания сложных интерфейсов. А их: 1) лучше создавать в другом инструментарии (читай Qt); 2) Nuklear скорее всего просто не осилит (за счёт малого количества компонентов).

      • 0
        ну… судя по коду все можно сериализировать, под капотом все пушается в буфер и рисуется. так что потенциально читать лайоут с какого-то редактора сделать не сложно. был бы редактор, кстати, можно попробовать использовать .dfm файлы Borland ide как вариант, редактор там норм
        • 0

          Ну платную проприетарную IDE, да ещё и доступную только под одну ОСь, вряд ли будут прикручивать к Open Source Public Domain проекту.
          С другой стороны, это Open Source. Я больше полугода сидел и хотел от Nuklear именно GDI+. Потом плюнул и реализовал недостающее сам :-)

  • +4
    Самая неожиданная реклама визуальной новеллы, что я видел.
  • +1
    А чем не устраивает QT? Да, объёмы больше, но и возможности не ограничиваются только GUI.
    • +1

      Почему стоит требование малого размера? Потому, что мне жаль из-за утилитки на 20 строчек заставлять пользователя каждый раз тянуть с собой ещё несколько мегабайт Qt. Если проект крупный и серьёзный, то никто не спорит, что инструментарий должен быть соответствующим. Только вот для совсем маленьких проектов я очень долго не мог найти ничего кроссплатформенного...

    • +4
      думаю, если собрать два самых частых вопроса в информационном поле нашей солнечной системы, они будут такими:
      — а почему не unity
      — а почему не qt
      • –1
        — а почему не Sciter?
      • –1
        — а почему не assembler и framebuffer?
  • +2
    Я было подумал пост десятилетней давности, присмотрелся, нет свежий. Не понимаю зачем так экономить когда речь по большому счету не идет об embedded системах.

    Лучше вложить свои силы создание красивого, правильного и простого установщика Qt runtime на системы где с этим туго. А для проектов побольше можно даже попробовать научить приложение дергать сей установщик, дабы подтянул необходимые компоненты.
    • +1
      Вы не сможете сделать утилиту на 100кб, портабельную и которая заработает под всеми дистрибутивами, которую просто скопировал в фаре и работай. Я пробовал, тут даже libstdc++ приходится линковать статически. Под виндой таскать с такими утилками несколько громадных dll тоже не айс, или копировать их в загрузочные пути чтобы все эти утилки заработали. Доп рантайм это гиблое дело, не заставите вы его никого ставить, все проекты эмбедят Qt внутрь. Под виндой даже С++ рантаймы новых студий ставить отдельно не хотят — эмбедят его установщик вместе с софтом. Причем версий рантайма установленных в системе придется делать 100500 т.к. разные утилки будет слинкованы с разными версиями Qt.
      А так да, Qt конечно рулит.
      • 0
        Так я и говорю, если правильно приложить к этому руки, то к продукту и люди потянутся и со временем превратят его в стандарт. И тогда, конечно, выпуск новой версии скажем раз в год строго с определенным тулчейном и определенной версией Qt — лучше чем клепать 100500 рантаймов. И вопрос портабельости в этом случае вполне решаем до определенной степени.

        Насчет студийных рантаймов, это очень странно что MS не может решить эту проблему по-человечески много лет. Давно могли бы сделать (полу-)автоматическую установку.

        А насчет размера бинарей. Я догадываюсь вряд ли количество подобных утилит дотянет в сумме до внушительных гигабайтов. А если и дотянет, то видимо время задуматься о выпуске пакета утилит с одним набором библиотек.
        • 0
          В ваших словах конечно есть истина, как и в моих. Как я уже говорил — я пытался заюзать Qt для данного сценария, проблема не только в размере, официальные сборки не статические, и в винде и в дистрибутивах. В винде приходится прикладывать dll, в лине или делать appimage\snap\flatpak или универсальный бинарь в который все надо линковать статически (из реп может не стоять по дефолту, а если бы стояло — версии разношерстные), на маке тоже придется постараться, в .app формате там приложение — это структура директорий. И универсальная сборка сильно усложняется. Для бльшого софта это норм, для мелкоутилок — ужас, ужас (./util.app/Contents/MacOS/util -f file :3 ).

          Размер тоже может иметь значение. Если это мелкоутилка лично моя — меня не будет сильно парить ее размер, разве что не сотни мегабайт. А вот если я в apk на андройд эту либу заюзаю, как в примере с аля-флешкой выше — меня парить уже будет. Или если я эту «флешку» в сайт какой встрою — тоже размер парить будет. Так же если это вдруг не персональная утилита, а какая-то сверх массовая, типа гнушных утилит, то мелкость по функции и черезмерная толстота тоже начнет вызывать вопросы даже на десктопе, а количество утилит в масштабах дистрибутива очень много.
        • 0
          Насчет рантаймов студий — все было хорошо, пока его не вынесли в WinSxS, так что dll из текущей диры уже не подхватываются, и ищутся из недр WinSxS по манифесту. В 2015 студии пошли на попятную и dll можно снова просто прилагать к проге.
  • 0
    Для этого есть Qt.
    Я лучше скачаю 10-20 МБ приложения, которое нативно выглядит и хорошо работает, чем 200 КБ примитивного GUI. Qt хорош, помимо прочего, большим количеством возможностей из коробки — и в плане GUI, и по взаимодействию с ОС.

    Речь не об embedded, конечно. Речь о том, что для десктопа 20 МБ — не размер, о котором нужно думать. Думать нужно о юзабилити и стоимости разработки хорошего приложения.
    • 0
      Qt может и выглядит нативно, но он не более нативен чем герой этой статьи. Точно также Qt рисует сам все контролы, все кроме самого окна.
  • 0
    Вижу на одном из скриншотов «Choose File».
    В readme проекта не нашел ответа на свои вопросы.
    Библиотека сама рисует диалоги choose file и тп? Или использует нативные? Или вообще нет такой фичи?
    • 0
      Нету такой фичи, у либы вообще нет зависимостей от системы и сама она такие диалоги не рисует. Но в демках и экзамплах уже есть зависимый от системы код.
  • 0
    А чем ваша библиотека отличается от уже существующих:
    http://webserver2.tecgraf.puc-rio.br/iup/,
    https://github.com/andlabs/libui?

    Они тоже написаны на С. Тоже весьма компактны. Используют даже нативный вид ОС в которой работают.
    • +1

      А Nuklear что, уже не существующая библиотека? ;-)
      IUP когда-то пробовал. Претендует на полность — много компонентов, свойств, конфигураций. И жирный исполняемый файл на выходе, несколько мегабайт. С тем же успехом можно wxWidgets взять, только писать код будет приятнее.
      libui значительно лучше, даже называют похудевшим wxWidgets. Только libui написана на С++, а не на Си. Так что как минимум несколько сотен килобайт прибавит. А то и больше, всё-таки компоненов там значительно больше, чем в Nuklear. Но за ссылку спасибо, как-нибудь помучаю эту библиотеку.

      • 0

        libui на C++? Где вы его в репозитории увидели? Я только в одном семпле.

        • 0
          Наверно имеется ввиду папочка windows. Зачем так сделано не очень понятно, может из-за того что студии не очень дружат с С99.
          • 0

            Чёрт, похоже на деформацию, папочку unix посмотрел, а windows даже не открыл :) Кстати, а darwin код вообще на ObjectiveC написан.

  • –2

    20 mb Qt много? У нас есть простая GUI утилика написанная на node.js + angular.js + electron. Так вот её дистрибутив весит 466 MB, который, конечно для удобства, заботливо положен в GIT репозиторий. (GIT LFS? нет не слышал...)

    • +1

      Да сейчас и на сотни гигабайт софт можно найти. Только что в этом хорошего?...

      • 0

        Да ничего хорошего, конечно, нет. Каждый раз открываю я эту тулзу и плачу. Только вот писал её один наш co-op student и стоила она компании практически ничего. Другой новый co-op student может её спокойно продолжать пилить, поскольку все они сейчас знают JS.
        Я хочу сказать то, что для постых задач нужна такая технология, которую можно отдать студенту, которая будет минимизирать стоимость разработки и для которой не нужен хардкорный программист который будут реализовывать загрузку изображений через OpenGL — для них и так работы хватает.
        Другое дело, если задача — сложная, но тогда, все рано, придется использовать Qt или что то подобное.
        Вот такие дела.
        А несколько лишних мегабайт никого сейчас не волнует (хотя повторюсь, без слез на нашу тулзу смотреть нельзя, но она работает)

        • +1
          Проекты разные и требования разные. А также сюда можно добавить бюджет и время. Кому-то 2Гб не проблема в браузере грузить а кому и 640кб хватит на все задачи. Но все замечу, что тема топика «идеальный GUI для микро-проектов», что какбэ должно намекать…
        • +1
          Никто и не говорит что у такого подхота тоже нету жизни, сейчас каждый второй мессенджер — электрон. И кстати в вебе сейчас тоже есть webgl, а инициализировать его через glfw даже проще. И я бы не сказал, что веб сейчас это такая простая технология сильно проще других областей. Я вот с электроном и nodejs тоже возился и проблем хватало, например когда ставится 2000 njs пакетов, у части есть native и бац — один не компилится, приехали.
          Тут все же немного разные области, одно дело одна своя утилита на 400 метров, раз приемлимо и проблем нет — почему бы и нет. Другое дело если каждая такая мелкая системная утилитка типа grep, meld, git gui, kdiff3 итд начнут весить по 400м, жрать по 2 гига и тормозить. Все же во все времена есть какой-то разумный баланс и раз кто-то уже инвестировал свое время в более оптимизированное решение, которым можно воспользоваться — это же хорошо.
  • 0
    Библиотека очень хорошо подходит под геймдев, потому, как и обещал, забрал библиотечку к себе.
    Сделал модификации, подключаемые ключами:

    NK_INCLUDE_DRAW_VERTEX_CUSTOM_FUNCTION
    не использовать штатный механизм буферизации данных меша
    в этом режиме, каждый раз, когда вычисляется данные по вершине полигона, вызывается функция
    typedef void*(*nk_draw_vertex_f)(void *dst, const struct nk_convert_config *config, struct nk_vec2 pos, struct nk_vec2 uv, struct nk_colorf color);
    что делать с этими данными уже решает пользователь
    (режим более заточен для отрисовки меша функцией glDrawArrays(GL_TRIANGLES))

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

    NK_INCLUDE_UNICODE_SUPPORT
    поддержка юникода вместо utf8
    то, чего я вно не хватало библиотеке

    NK_INCLUDE_DISABLE_KEYBOARD_EDIT
    отключает клавиатурный ввод и отображение курсора/селекшина

    также были добавлены мелкие полезные мелочи

    Это все уже работает, вот пример интеграции библиотеки в мой игровой движочек:
    http://casualgum.com/public/nuklear_gui.html

    Сейчас занимаюсь исправлением багов и стабилизацией для пулл реквеста.
    Изменений очень много, могут и не канонизировать, так что, кому интересно, пока все наработки тут:
    https://bitbucket.org/pascualle/nuklear
    • +1

      NK_INCLUDE_DRAW_TEXT_CUSTOM_FUNCTION
      Ну рисовалку картинок оно точно на драйвер перекладывает. Разве со шрифтами не так же? По-моему, это уже есть в Nuklear. GDI+ явно не использует стандартную рисовалку шрифтов от Nuklear.


      NK_INCLUDE_UNICODE_SUPPORT
      Не подскажете, почему не UTF8?

      • 0
        NK_INCLUDE_DRAW_TEXT_CUSTOM_FUNCTION
        в GDI+ переделан полностью весь механизм работы с NK_COMMAND*
        а при этом ключе просто выключается все, что связанное с текстами при стандартной работе с nk_convert()
        нужно только определить функцию для рендера текста:
        typedef void(*nk_query_font_glyph_f)(nk_handle handle, float font_height,
        struct nk_user_font_glyph *glyph,
        nk_rune codepoint, nk_rune next_codepoint)
        и функцию определения ширины для логики лайоута
        typedef float(*nk_text_width_f)(nk_handle, float h, const nk_tchar*, int len);

        NK_INCLUDE_UNICODE_SUPPORT
        ибо не utf единым, юникод является типом текстовых данных по умолчанию для многих библиотек, тем более тип wchar_t и работа с ним — нативная часть c/c++, а utf — это все-таки чужеродное, хоть и удобное
        • 0

          Nuklear.h, 1156:


          1.) Using your own implementation without vertex buffer output
          So first up the easiest way to do font handling is by just providing a
          nk_user_font struct which only requires the height in pixel of the used
          font and a callback to calculate the width of a string. This way of handling
          fonts is best fitted for using the normal draw shape command API where you
          do all the text drawing yourself and the library does not require any kind
          of deeper knowledge about which font handling mechanism you use.
          IMPORTANT: the nk_user_font pointer provided to nuklear has to persist
          over the complete life time! I know this sucks but it is currently the only
          way to switch between fonts.
          2.) Using your own implementation with vertex buffer output

          While the first approach works fine if you don't want to use the optional
          vertex buffer output it is not enough if you do. To get font handling working
          for these cases you have to provide two additional parameters inside the
          nk_user_font. First a texture atlas handle used to draw text as subimages
          of a bigger font atlas texture and a callback to query a character's glyph
          information (offset, size, ...). So it is still possible to provide your own
          font and use the vertex buffer output.
          • 0
            Так точно, я читал это. Но что, если нужно использовать vertex buffer, но абсолютно нет нужны инициализировать и загружать шрифт? Он уже загружен средствами другой подсистемы, и все, что нужно знать nuklear — это id шрифта, размер шрифта и имплементация функции float your_text_width_calculation(nk_handle handle, float height, const nk_tchar *text, int len)
            Все остальное, такое как texture atlas, query callback и тд, не нужно.

            Тем не менее, NK_INCLUDE_DRAW_TEXT_CUSTOM_FUNCTION требует от пользователя заполнить структуру nk_user_font:
            font->userdata.id = font id стороннего шрифта
            font->height = размер стороннего шрифта
            /* имплементация your_text_width_calculation */
            font->width = nk_custom_font_get_text_width;
            /* инитиализация nuklear с nk_user_font */
            nk_init_default(инстанс_nuklear.ctx, font);
            /* функция рисования текста в vertex buffer стороннего движка */
            инстанс_nuklear.ctx.draw_list.draw_text = nk_custom_draw_list_add_text;

            Другими словами, новый ключ NK_INCLUDE_DRAW_TEXT_CUSTOM_FUNCTION расширяет возможности nuklear, без избыточности, более того, при этом ключе удаляется весь «ненужный» код работы с шрифтами в nuklear. Правда, использование этого ключа максимально эффективно в работе с ключом NK_INCLUDE_DRAW_VERTEX_CUSTOM_FUNCTION, так как в такой завязке мы получаем доступ к вертексам извне
            • 0

              Тогда всё отлично, спасибо! Прошу прощения, изначально не правильно понял смысл. Жду эти изменения в master'e Nuklear

              • 0
                есть пока противная бага с тачскрином, nuklear почему-то адаптирован только под «непрерывный инпут», а также где-то я напартачил с редактированием текстовых полей. работаемс, в общем, пока
  • 0

    (написал выше)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.