Как я перестал бояться и переизобрел QML

    Что?


    Привет, Хабр! Прошло очень много лет, с тех пор как я писал сюда. Надеюсь, время тебя/меня не слишком/слишком потрепало.

    Я хотел бы написать о нашем опыте переосмысления идей QML. Qt — прекрасная (по совокупности заслуг) библиотека, и хотя её внутреннее устройство местами вызывает вопросы, но она дала миру не только кросс-платформенный UI тулкит, но и цельный профессиональный набор инструментов: Дизайнер, Креатор, Лингвист, и, конечно же, Qml. Результатом этого переосмысления стал наш скромный проект, который превращает qml в html5/javascript для разных платформ, и даже позволяет собирать простые android приложения используя Cordova.

    Qml всегда привлекал нас (небольшую неизвестную группу QML-адвокатов, как мы себя называем, надев монокли и цилиндры) своей абсолютной выразительностью в плане разработки интерфейсов, и поэтому каждый из нас использует их для разработки пользовательских интерфейсов и сайтов.

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

    Исходные коды доступны на github, там же лежат исходные коды сайта, примеров и библиотека контролов, которые мы используем для всех своих проектов. Документацию и уроки можно посмотреть на нашем сайте, pureqml.com.
    Если вы чего-то не понимаете, можете присоединиться к группе поддержки в Telegram, мы постараемся ответить на все вопросы в реальном времени.

    Одно из бесплатных приложений, которые мы сделали, был порт игры Fontanero, она должна быть доступна в маркетах LG/Samsung.

    Ну а дальше можно не читать!

    Как мы дошли до жизни такой


    Всё началось в уже-далеком 2010-ом году, когда мы начали писать встраиваемое ПО (и интерфейс пользователя) в одной крупной корпорации для линейки разношерстных устройств на всевозможных платформах, доступных сейчас: arm, mips, x86, sh4, не хватало только sparc…

    Основную проблему мы для себя сформулировали так: UI должен быть быстрым, дешевым и хорошим, и, чтобы не надо было выбирать только два пункта из этих трех. Ресурсов было очень мало (полтора программиста), поэтому хотелось, чтобы программирование UI было легким и приятным, а программисты не страдали, не плакали, и не убегали, а фокусировались на решении бизнес-задач, вместо ручного отслеживания координат. HTML отпал сразу же, отчасти потому, что самое первое устройство было на arm926xxx (armv5) и имело на борту 32Мб оперативной памяти, из которых только 23Мб было доступно для user-space приложений (а также armv5 имеет смешное ограничение на 2G виртуальных адресов для всех процессов в сумме, поправьте меня, если я ошибаюсь), что очень сильно сужает область для поисков.

    После анализа существующих решений, наш выбор пал на относительно новый (тогда) язык и технологию — QML, что было совсем не удивительно, учитывая предыдущий позитивный опыт разработки с Qt. Исключительно простой и наглядный, мы сразу же решили, что это то, что нам нужно. Появившийся через неделю, искрящийся от модных анимаций, весьма функциональный прототип, еще пуще убедил нас в правильности выбора.

    QML — (достаточно) прекрасен


    Самое прекрасное в QML то, что он прячет от программиста всё, за исключением, собственно, UI. Надо просто брать замысел в руки, и выплескивать на холст!

    Декларативный подход очень нагляден и прост в использовании. Переиспользование компонент интуитивное, и, для простых случаев, — очень лаконичное. Это позволило нам сделать полноценный UI (менюшки, приложения, настроечки, расписания и прочие штуки), буквально за пару месяцев, силами двух программистов.

    На утаптывание Qt мы потратили немало времени, но оказалось, что даже кастомные сборки, без капли лишнего, никак не влезают ни в 8, ни в 16 Мб флеш-памяти. Грусти нашей не было предела, ведь мы уже жили в мире, где embedded-интерфейсы перестали быть унылыми и возмущались, вспоминая времена, когда не было Qt QML.

    В тот вечер, мы с коллегой коротали вечер за бутылочкой Циндао в одном из отелей Шеньчженя (на 48-ом этаже!), думая о том, можно ли сделать QML, но на C++, и, заодно, проверить на прочность возможности той самой печальной платформы на arm926. Оказалось, что всё не так уж и плохо, и возможностей процессора хватает чтобы рисовать прозрачные красивые окошки даже софтверно, а ведь там был и аппаратный ускоритель 2d графики!

    Засучив рукава и отбросив Циндао, мы начали яростно компилировать, и, уже через пару недель мы уже имели свой QML с C++ вместо javascript. Это был наш первый собственный QML, который мы полировали довольно долго, до победного конца.

    Но C++ — это достаточно хардкорно, и это накладывает свои ограничения, например, вы не можете распространять приложения для разных платформ, нативный код очень долго компилируется, более требователен к мозгу программиста, и требует бóльших вложений. Поэтому, через пару лет, когда мы с (другим) коллегой коротали вечер за пирожками в одном из кофешопов Амстердама, то придумали, как вернуть javascript (в лице v8) в нативный код.

    Эта предыстория может быть не очень интересна, ведь те два QML остались в прошлом, вместе с той самой корпорацией, где они родились. Они так и не предстали перед широкой публикой в качестве средства разработки, но UI, построенный на этой технологии, повседневно использует порядка шести миллионов человек.

    Наши дни (полтора года назад)


    После ухода из этой большой и страшной корпорации, нам захотелось также быстро и просто разрабатывать интерфейсы, и заодно появилась необходимость написать большое и сложное приложение для SmartTV, сразу на 5 (!) платформ. Android для телевизоров тогда еще не вышел, и все SmartTV тогда (как и большинство сейчас) предлагали SDK на базе HTML, продвигая свои фреймворки и либы для облегчения жизни программистов (например, caph от samsung), но это скорее усложняет процесс, так как реализацию одного UI нужно было переписывать под фреймворк каждого конкретного производителя. Мотивация их (производителей) телевизоров к использованию web-технологий понятна, но реализация становится весьма болезненной по мере увеличения сложности приложения. Имея за плечами пятилетний опыт писания собственных QML движков, мы решили сделать еще один собственный QML (нужно больше велосипедов!), но уже для SmartTV в частности, и для HTML в общем.

    Так и зародился наш скромный проект.

    Основной инстинкт принцип


    Всё устроено почти как в qml, все компоненты описываются в .qml файлах, в .manifest описывается структура приложения. Дальше в дело вступает транслятор/транспайлер(?) QML в html5/javascript: генерируются и подключаются сигналы, обновляторы, прототипы и конструкторы. После трансляции получается компактный и быстрый javascript-файл, вместе с html-запускателем, требующий только Modernizr.

    Отличительной особенностью является то, что мы написали QML на QML, все core компоненты написаны на qml и javascript, используя наш тулчейн, сам транспайлер всего лишь раскладывает файлы по пространствам имен и генерирует то, что обычно пишут руками.

    Трудности перевода и велосипеды


    QML диалект, который мы используем, очень похож на оригинальный QML. Самое главное изменение — мы переделали логику фокуса, сделав его более простым и безопасным.

    В целом, мы стараемся сохранять совместимость с Qt QML и иногда устраиваем крестово-совместительные походы по расхождениям.

    Так как мы используем HTML5 как основную платформу (наверное, уже не очень модно говорить так, я не знаю точно), то мы используем HTML как простую систему рисования 2d графики, позиционируя элементы (div) абсолютно, относительно родителя. Это позволило нам полноценно реализовать примеси, например, разрешить любому элементу обрабатывать события hover или click, не используя страшный монстр MouseArea. Так же можно добавлять Border, Gradient или Drag-n-Drop в произвольные элементы, не создавая дополнительный элемент, и не создавая связку Item-MouseArea.

    Текущее состояние


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

    Создан генератор документации и навигатор по нему, как и скелет самой документации, при помощи похожих на doxygen аннотаций. Требуется навести порядок в библиотеке компонентов.
    Доработать инструкции и инструментарий для Windows и MacOS.

    У нас есть масса идей по оптимизации, наращиванию функционала и платформенным доработкам и прочему.

    И тем не менее, ядро проекта уже достаточно стабильно, и мы, к сему моменту, успели выпустить несколько коммерческих проектов (и нескольких некоммерческих) на нашем PureQML.

    Очень ждем ваших отзывов, а если кто-то захочет сделать что-то реально работающее, это будет просто прекрасно!

    Всем кто дочитал эту исповедь до конца, огромное спасибо!

    Если эта статья хоть кому-то будет интересна, мы можем продолжить рассматривать наше видение QML, развитие примесей, интеграция с разными платформами на разных уровнях, декларативно и нет, улучшение языка, добавление размерности в декларации (%, em, pt).

    Мы пока решили не открывать исходные коды для smartTV платформ, но, вообще, рассматриваем такую возможность. Если вы хотите получить версию для SmartTV, напишите в комментариях, мы подумаем в каком виде это можно сделать.
    Поделиться публикацией
    Комментарии 21
      +1
      Поэтому, через пару лет, когда мы с (другим) коллегой коротали вечер за пирожками в одном из кофешопов Амстердама


      Что то не припомню я пирожков в Амстердамских кофешопах, разве что с мухаморчиками.
      Или это сейчас так называется? :)

      Между прочим после этих самых «пирожков» очень прет на умные мысли :)

      Если эта статья хоть кому-то будет интересна, мы можем продолжить рассматривать наше видение QML

      Конечно продолжайте!
        +1
        Что то не припомню я пирожков в Амстердамских кофешопах

        space cake ;)
        +2
        Интересный проект. Продолжайте писать.

        Правда некоторые примеры не работают


        Еще интересует транслятор QML в C++, можно немного подробнее.
          +4
          Спасибо за то что посмотрели, на эту тему с утра уже была буря в чятике, починят/починили уже, наши лучшие полтора программиста работают над этим!

          Про C++, к сожалению, вся интеллектуальная собственность осталась в той корпорации, и у нас даже был зеленый свет на открытие частей, но мы так и не собрались, ну и там ничего интересного нет, оно просто достаточно аккуратно написано, имеет постоянный memory footprint, и не аллоцирует больше чем 8 мегабайт, вместе со всеми картинками и приложениями. :)

          По идее, вы можете взять грамматику и промежуточное представление из нашего проекта. Но проблема смены языка в том, что весь рантайм придется полностью переписать, так как код во вставках станет c++. Но это, возможно, не такая уж и большая проблема. Мы использовали дополнительные native блоки, которые могли вставлять свое содержимое в код результирующего класса или прямо в header/cpp файл.

          В этот раз мы решили зайти с другой стороны. Сделать layout-независимый javascript-движок, который может исполнятся в нашем нативном браузере (не-html, см. скриншот ниже).

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



          +5
          Просто суперкрутая идея, я постоянно думаю о том что все современный веб стек это полнейший дурдом и на его месте должен быть нормальный язык разметки интерфейсов.
            +4
            Я тоже постоянно думаю об этом, почему веб пошел своим путем, а не путем даже java.awt еще тех древних времен (ответ конечно есть, но я им не очень удовлетворен). Прочитав статью (признаюсь, знал об этой теме ранее, хотя отношения к ней не имею) я что-то не подумал об этом. Наверное потому что на Qt/QML практического ничего ни разу не писал. Вечером всё установлю, поверчу в руках.
              +2
              Если вам нужна будет помощь, вы можете присоединиться к нашей группе в телеграмме, обновил пост, поставил ссылку на группу.
                +2
                Нет, я сам, Вова, попробую, а потом тут напишу о всех попутных косяках, костылях в приступе сарказма. Конец сарказма.
                  +2
                  я не узнал тебя в гриме! :D
              +2
              да, на сыром html/js писать можно убиться, слишком низкоуровнево это всё сейчас стало, нужно поддерживать миллион вещей и бороться с разными особенностями, например невозможностью что-то выровнять по вертикали, без хаков, ну и миллион других вещей.
                +3
                потому что они для этого не предназначались изначально, всё делалось для гипертекстового веба, но постепенно обрастало костылями, сейчас про гипертекст все забыли, основной веб это приложения, а браузер стал виртуальной машиной для этих приложений.
                В html с помощью элемента div, джаваскрипта и классов стилей (!) делают компоненты графического интерфейса, которые по идее должны быть стандартными.
                А непонятно откуда взявшийся javascript из инструмента для выведения alert окошек превратился в что-то типа языка программирования, хотя и отягощённого родовыми травмами.
                Всё это печально, лучше бы питон и qml былы на их месте.
              +2

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


              Но все-таки остаются вопросы.


              Прежде всего поддержу комментатора выше: очень интересует трансляция QML в С++.
              Делали ли вы какое-то сравнение с родным QtQuickCompailer-ом?
              Как прогнозы относительно существующей и грядущей генерации кэша?
              Планируете ли Вы продолжать крестовые походы в этом направлении?


              Большое недоумение вызывает выбор в пользу HTML\JS и всей остальной обвязки.
              Вы начинали с того, что вывели в мир новую связку QML+С++(вместоJS), я так понимаю в 10-м году это был еще Qt Quick 1.0. В результате QML-код не стал компилироваться в полноценный бинарник, а добавилась еще одна прослойка интерпретации\трансляции. То есть то, о чем сейчас много шумят: между нативным фреймворком и кросплатформенным Вы выбрали кросплатформенный.
              Почему? Поправьте, если я где-то неправильно понял.


              Хотелось бы еще узнать о том, как решен\решается вопрос с Native Look & Feel.
              Если говорить о телевизорах, те же Android-TV и AppleTV, то они таки имееют определенные особенности.
              Буду очень признателен, если поможете найти это в примерах.


              Касательно производительности. Очень хочется больше Цифръ(!). Очень сложно поверить, что транслирование в HTML дало такой существенный прирост (говорю о дне сегодняшнем) по сравнению с QML.
              У ребят из SpbTv имеется нативный низкоуровненый фремворк с поддержкой того же Qt: в этой обвязке они запускают стримовое видео на старых чернобелых Palm-ах, а там всего около 10 Мб памяти.


              Хотелось бы также узнать сколько сейчас разработчиков трудятся над проектом?
              Какие у вас перспективы? Простите, если вопрос лишний.


              Еще раз спасибо за статью и код.
              Надеюсь это не последний рассказ.

                +2
                я выше немного написал про c++

                Сравнение с оригинальным qtquickcompiler'ом не делали, у нас главный сравнитель была та железка на armv5, по мощности как древние фичернокии, но разрешение побольше. Мы не использовали код Qt, всё было свое, включай транспайлер в C++. Изначально мы транслировали Qml в c++ и использовали нативный код, без всяких прослоек. Сейчас мы делаем по другому, т.к. вектор немного изменился, а выбор в пользу html был сделан только потому что это позволит сразу же расширить количество платформ на браузеры, мобильные браузеры, и телевизоры. В большинстве smartTV сейчас html/js API, а если возиться с нативом, то можно очень быстро устать, и вряд ли вендоры позволяют так легко нативные куски запускать на телеках.

                Вопрос с Native Look & Feel можно решить двумя способами: вы/мы можем создать qml компоненты вокруг нативных контролов, или эмулировать стилями, как это делает Qt. AppleTV мы пока не поддерживаем, к сожалению. У нас пока не было задачи такой, мне кажется в телевизоре вектор больше на создание индивидуального стиля для приложения, чтобы он соответствовал корпоративному стилю, и т.п.

                Цифры я к сожалению, не могу предоставить, я уже больше года не работаю в той корпорации, но memory footpring ui, сравнимого с телефонным, лаунчер, менюшки, приложения простые, потреблял постоянное количество памяти, устанавливаемое заранее, у нас было 8Мб.

                Разработчика сейчас всего три, включая меня. Перспектив никаких нет, ахаха. Мы просто используем это в небольших коммерческих и некомерческих проектах, ну и для баловства тоже используем.
                  0
                  И ещё немного написал. Скажите, зачем вам qml-c++?
                    0
                    Скажите, зачем вам qml-c++?

                    • Дык есть случаи, когда ресурса мало, как и у вас было.
                    • Когда jit запрещается позицией тирана-властителя.
                    • Просто страшно интересно.
                +1
                А вы не задумывались о связке QML/WebAssembly. Мне кажется очень перспективная тема.
                  0

                  Задумывались слегка, но для html баттлнеки не в js коде(хотя время запуска с WebAssembly было бы лучше), а в том сколько работы ложится на браузер при изменении того или иного стиля.
                  Вообще, WebAssembly, наверняка, хорошо зайдет, если рендерить в канвас. Да, спасибо за идею.

                  0

                  А вы не смотрели на qmlweb?
                  Присоединяюсь к просьбе о подробностях QML C++.

                    0
                    Ну там в целом ничего интересного про c++, в целом схема такая же:

                    1. qml расширен native { } вставками в тело компоненты и тело файла, если native мимо компоненты, чтобы можно было легко колбасить нативные компоненты, например:
                      Image
                      { 
                        native
                        {
                           qml::DiscardableSurfaceHolder _image
                        }
                      }
                      


                      большая часть рантайма написана на таком qml, чтобы долго не возиться
                    2. парсер парсит, создается промежуточное представление, генерятся классы 1-в-1 компонента-класс, практически как бы вы руками писали
                      class Rectangle : Item
                      { 
                        qml::Property<int> x;
                        qml::Property<int> y;
                      };
                      

                    3. profit!


                    Мне больше интересно, зачем вам нужен декларативный C++, мы делали из бедности, т.к. Qt не лезло.

                    Мы сейчас ведем разработку ультра-лайтового js, который залезет везде где есть c++, без депенденсов, и вроде даже каких-то результатов добились. 10-15 раз меньше памяти, работает 20-120% скорости v8 на arm :) 300к либа, пока без рантайма (но с практически готовым языком)
                      +1
                      На qmlweb — смотрели, и когда-то, на заре хотели его использовать, но все таки решили сделать свой.
                      Если смотреть глобально, то и у pureqml, и у qmlweb, общая цель — облегчить разработку UI для современных платформ. Но подходы к достижению этой цели несколько разнятся.
                      QmlWeb ориентируется на полную совместимость с Qt QML, что безусловно имеет свои плюсы, в PureQML, мы тоже стараемся поддерживать совместимость, но скорее в одну сторону, чтобы можно было оригинальные Qt QML приложения запускать на PureQML. Поскольку браузеры, десктопные, мобильные или телевизионные заточены определенным образом, в PureQML используется ряд расширений для пущей производительности, если использовать их в разработке, то в обратную сторону, на оригинальном Qt QML, приложение не заработает, ну или придется кое что переписать. Ну или же не использовать расширения и есть кактус.
                      QmlWeb целится на HTML-based платформы. В PureQML HTML хоть и самая проработанная из платформ, но есть еще и нативная и планы по влезанию на Android/iOS по тому что принципу, что и, например, React Native.
                      Есть конечно же еще множество отличий, но это уже, больше, детали.
                      Я бы сказал, что PureQML и QmlWeb, на данном этапе, дружественно дополняют друг​ друга, неся изящество декларативного программирования в массы.
                      0
                      whoozle Я тут случайно наткнулся на весьма интересный проект — ENAML, он умеет кроссплатформенный гуй, но вот веба похоже не имеет, хотя под капотом там есть Qt, может можно к ним прикрутить PureQML и получить ещё и веб?

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

                      Самое читаемое