Cіпласпластик
531 subscribers
161 photos
35 videos
2 files
253 links
🇺🇦 Про айті та дотичні теми загалом, ну й трохи про C++.

Мої емоджі:
https://t.me/addemoji/AdaptiveDevIcons
https://t.me/addemoji/VehicleBrands
Download Telegram
Розповім ще невеличку історію про 💻 та #QML, але не стільки з технічними деталями, скільки з архітектурними.

Отже, частиною Qt є UI-фреймворк під назвою Qt Quick. Він звісно на С++ написаний, але користувачі переважно на QML пишуть. Всі візуальні елементи там є нащадками Item. Ну й за роки розвитку він вже добряче навбирав у себе різних спільних властивостей та став дещо важкеньким.

Серед базових важливих властивостей, що були там з самого початку, є так звані anchors — механізм дуже легко робити flexible UI. Наприклад, пишете
height: 35
anchors.bottom: parent.bottom

і поточний елемент завжди буде 35 пікселів заввишки і завжди прикріплений до нижнього краю контейнера, в якому лежить. Виглядає, як якась потойбічна магія для тих, хто пише на CSS, я розумію.

Хоч на анкорах майже будь-що можна зробити, та не завжди це зручно. Якихось більш високорівневих лейаутів не було, й згодом їх додали окремим модулем QtQuick.Layouts. Відтоді стало можна писати якось отак:
RowLayout {
TextField { Layout.fillWidth: true }
Button { text: 'Submit' }
}

Ця штука автоматично позиціює елементи в рядок. Причому поле для вводу текста розтягнеться на всю можливу ширину, а кнопка буде мінімально можливого для себе розміру. Доволі зручно, хоча в певних випадках вкрай важко змусити ці лейаути робити те, що тобі треба, бо вони переускладнені відчутно. Не flexbox, звісно, але у мене в голові червона лампочка складності вже мерехтить.

Та весь кайф був у тому, що ніхто QtQuick.Layouts не навʼязував. Не подобається, як вони працюють? То напиши свій (на C++)! Так і зробив мій друган, що тоді був девелопером у моїй команді. І тепер його лейаут «катається» у сотнях тисяч Мерседесів з MBUX.

Та, схоже, не всім це було до душі. Виявилося, що комусь занадто складно розставляти fillWidth/fillHeight у потрібних місцях 🤦🏻‍♂️ Це, як на мій погляд, не велика проблема, бо QML дозволяє це суперлегко вирішити створенням нових компонентів. Для цього треба або новий файл створити (1 компонент = 1 файл), або прям inline написати на кшталт:
component FormField: TextField {
Layout.fillWidth: true
}

RowLayout {
FormField {}
Button {}
}

Ну, типу… все! Що може бути краще?

Але якийсь черговий геній в Qt знайшов можливість «пакращєння»:
1) він додав у базовий Item властивість sizePolicy, яка має вказувати кьютовому лейауту, чи розтягувати елемент, чи він мусить мати фіксований розмір.
2) Потім він нахуєвертив «sensible defaults» в усі контроли, що наслідують Item, тобто всі кнопки, текст-філди, слайдери й таке інше.
3) Ці sensible(!) defaults миттєво наламали KDE Plasma, де все поплило, бо не такі вони й sensible виявилося.
4) І на додачу, sizePolicy ще й частина private API, тобто для своїх кастомних лейаутів це буде проблематично використати. Отже, QtQuick.Layout тепер прибитий цвяхами до QtQuick.
Наразі вирішили цю фічу зробити тимчасово opt in, однак, проперті вже там, тож кожен Item позаяк займає більше памʼяті, ніж раніше.

А які задачі ви вигадуєте собі на роботі, щоб не складалося враження, що сидите без діла? 🤣
Please open Telegram to view this post
VIEW IN TELEGRAM
😱3😁2😢1👀1
Де це Сіпласпластик знов подівся? Працює, мабуть…

Ще б пак працює!

Отже, у вільний час, якого на жаль не так багато, потроху допомагаю перекладати гру українською. І щоб перевірити локалізацію на власне грі, треба стягнути поточний файл з перекладом з Crowdin та закинути у потрібну теку.

От тільки файл — це CSV, і Crowdin автоматично огортає кожне значення в лапки, а парсер гри цього не розуміє, бо там розробники не заморочувалися. Ну й додаткові ще якісь реквайрменти до того файлу є.

Що роблять нормальні люди у такому випадку? — Виправляють все файнд-реплейсом у ноутпаді.
Що роблять адекватні люди з навичками програмування? — Пишуть скрипт на 💻 у три рядки, який виправлятиме все автоматично.

Що роблю я? — Я пишу рушій для запуску «правил», написаних на #QML 😅

Отож правила + опціональний логотип (гри) + додаткові файли для копіювання лежать в бандлі. Концепція бандлів з #macOS мені дуже подобається: це така тека з різноманітним мотлохом, але система відображає її як файл і, коли дабл-клікаєш, відкриває відповідну програму. На вінді, звісно, так не працює, тому я просто всередину бандла поклав ще один додатковий порожній файл з кастомним розширенням, і дабл-клікаю там вже по ньому.

QML-рушій крутиться в UI-треді, тож коли йшла обробка файлу, все завмирало, чим дуже мене дратувало. Але виявилося, що можна мати декілька рушіїв в одному процесі! Мені так навіть краще. Я в окремому треді запускаю рушій для опрацювання правил, а в UI-ному тільки… UI. І вони один з одним комунікують там якось сигналами. На одному з етапів розробки у мене так летіло 50к сигналів в секунду 😄, тому UI все одно не реагував — довелося трохи оптимізнути. Зараз там, думаю, ну сотня тих сигналів, може, якщо не менше.

Користувач просто драг-н-дропає файл у вікно, й воно фігачить. Наразі є декілька видів правил:
FileRule отримує на вхід чисто імʼя файлу й далі робить з ним ті перевірки, що хоче, в колбеці ensure.
ItemRule запускається для кожного рядку тексту, тож отримує цей рядок та його індекс. Окрім того, можна задефайнити ще fix, який автоматично щось виправлятиме.
InstallCurrentFile дозволяє поточний файл закинути у якусь теку, опціонально під іншим імʼям.
InstallFiles — майже те саме, але копіює якісь статичні файли з бандлу.
• Окрім того, існує Group, щоб можна було групувати декілька рулів, а значить — виносити їх в окремі реюзабл-файли! Їх можна вкладати одна в одну, й воно врешті просто «розчиняє» їх, роблячи щось на кшталт flatten.

Люди з команди поки що не дуже оцінили прикол, відреагувавши доволі вʼяло — мабуть, тому що треба текст перекладати, а не хуйнею маятися 😅 Але мене прям бісило руками це робити щоразу, тож я не встояв, бо коли мене щось з інструментів дратує, я весь час про це думаю й не можу сфокусуватися на роботі.

Думаю згодом ще додати можливість порівнювати рядок з оригіналом + підтримку інших форматів на кшталт XLIFF + автоматичний апдейт з Crowdin, щоб руками ото не качати. Але поки що мені й так норм.
Media is too big
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥53👍3
This media is not supported in your browser
VIEW IN TELEGRAM
Я обожнюю #QML. Все-таки Nokia сильно випередила час із ним.

Ліричний відступ для тих, хто не в темі: QML — це така мова в 💻. Вона декларативна, тобто ви описуєте, що хочете отримати, а не послідовність кроків для досягнення мети. Всі властивості обʼєктів у ній — реактивні, тобто, якщо ви пишете, що height: width / 2, то значення висоти оновлюватиметься щоразу, як оновилася ширина. Ну й на додачу можна писати локальні обробники сигналів на імперативному 💻, якщо треба. І все це швидко працює й рендериться на GPU. Непогано як для технології 2009 року отже.

Люди, правда, зазвичай ототожнюють QML (мову) і Qt Quick (один з UI-них фреймворків від Qt), але мову можна використовувати не тільки для UI.


Отож пишу на QML багацько. Останні пів року чи рік з ґітгабівським копайлотом. Проте для робочих проєктів для замовника копайлот не можна використовувати, бо досі з легальними питаннями не розібралися.

Вирішив спробувати приготувати QML-ний копайлот самостійно. Рецепт такий:
1. Беремо Ollama.
2. Додаємо FIM-модель (Fill-in-the-Middle) для QML, скажімо параметрів на сім-тринадцять мільярдів до смаку.
3. Ставимо у VS Code розширення, яке спілкуватиметься з моделлю.
4. ???????
5. PROFIT! 🥳

Гарні новини: модель існує й навіть офіційна від Qt. Ну, взагалі-то навчити з нуля модель такого розміру — дорого й невигідно, тому насправді це Meta-вська CodeLlama, яку дотренували на якомусь відкритому QML-коді типу офіційних прикладів.

Що взагалі робить будь-яка така модель? Ви закидаєте в неї код (текст), воно його токенізує якось (у кожної моделі власний токенізатор), а потім генерує декілька наступних токенів, які ми перетворюємо назад на текст. Тобто ви пишете import , а воно дає наступний токен чи декілька, які з 99% ймовірністю будуть QtQuick\n.

Але код ми не пишемо як повість на друкарській машинці — ми часто повертаємося кудись в середину, щось додаємо, міняємо, видаляємо тощо. Як же бути?

Якщо ми передаватимемо тільки текст до курсора, щоб модель щось додала від себе, то можемо загубити багато важливого контексту після, й доповнення не буде надто корисним.

Щоб розв'язати цю проблему, всі FIM-моделі дозволяють певного роду розмітку (насправді всі інші LLM також). Наприклад, CodeLlama дозволяє передавати їй текст у таких форматах:
<PRE>Текст до курсора<MID>
<PRE>Текст до курсора<SUF>Текст після курсора<MID>
<SUF>Текст після курсора<PRE>Текст до курсора<MID>

Тут токен <MID> каже моделі, що ось з цього місця — твій вихід, будь ласкава.

Погані новини: для VS Code я знайшов якесь розширення Llama Coder, і воно вже вміє працювати з CodeLlama, а також дозволяє вказувати власну модель. Але виявилося, що промпт воно формує у вигляді <PRE>…<SUF>…<MID>, а ці QML-ні моделі якось так дивно перенавчені, що у відповідь на це видають повну маячню.

Вони прям вимагають, щоб формат був <SUF>…<PRE>…<MID>. Довелося форкати розширення й міняти. По дорозі знайшов і виправив ваду з неправильною вичиткою налаштувань, а також додав кропаль покращень від себе.

Це запрацювало, хоча не сказати, що швидко. Точніше прям неприємно на моєму M1 Max / 64 GB — користуватися неможливо. І це 7 мільярдів параметрів, а не 13! Зате повністю локально, і доповнює вельми адекватно, щоправда форматування пливе.

Дивитимусь далі, що з цим можна ще зробити, щоб було зручно. Ненавиджу довгі мануали — треба, щоб однією кнопкою все встановлювалося ))
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16😁31
Декілька років тому 💻 на своєму World Summitʼі мала доповідь, в якій чувак натякав, що було б цікаво використовувати цю бібліотеку в програмах іншими мовами.

Зараз Qt можна використовувати з C++ (очевидно), плюс є офіційні привʼязки для Python під назвою PySide. Ще промайнули якісь дивні поробки для інтеграції з 💻. На цьому все. Існує безліч неофіційних, та щось довіри до них нема.

Я вже якось згадував, що #QML як мова для використання фреймворка Qt Quick — це одна з останніх вагомих причин, чого я досі користуюся C++. Просто мені подобається робити UI і подобається, коли врешті він працює достатньо швидко й не вимагає 2 ГБ оперативки, як це нерідко буває з туду-програмами на електроні. Втім C++ у своєму поточному стані дійсно далека від приємної мови, хоча я потроху прямує до неї.

Так-от місяць тому пройшов черговий QtWS, де вони нарешті анонсували так звані Qt Bridges. Поки що жодної конкретики, але за їхніми розповідями це якась достатньо високорівнева апішка для інтеграції QML-ного рушія (і, може, не тільки) в програми іншими мовами. Першими їхніми обранцями стали: 💻, Kotlin 💻 і Java 💻, Python 💻, Rust і Swift 🕊. Я особисто найбільше зацікавлений в останньому, бо під час Advent of Code 2024 мені загалом ця мова сподобалася. З іншого боку дуже хотілося б ще мати змогу писати на QML разом з 🦶. Ну й з Janet 👩‍🦰 ще б теж непогано ))

Найбільше в усьому цьому мене зараз хвилює навіть не технічний бік питання, а легальний. Nokia в свій час перевела Qt з GPL на LGPL, що зіграло на руку популяризації бібліотеки. Але зараз ми бачимо, що Qt Group в пошуках додаткових джерел для заробітку робить навпаки: створює нові модулі, інколи попередньо задепрекейтивши «старі» LGPL-ні, і релізить їх тільки під GPL та комерційною ліцензією. Наприклад, Qt Graphs, Qt HTTP Server, Qt Lottie Animation, Qt Quick 3D тощо.

А як хотілося б мати змогу писати UI на QML, а бізнес-логіку на чомусь компільованому, потім збирати це в один невеличкий бінарь — і щоб це все ще й безплатно! 🤑 Хоча, мабуть, легше вже свій рушій для QML написати натомість.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🤔1👀1
Я користувався й у деяких проєктах досі користуюся білд-системою #Qbs (неодноразово писав вище). Але як же вона мене замахала! Це просто квінтесенція того, як робити не треба.

Почав користуватися нею через очевидні переваги:
1) декларативна мова, що базується на #QML, з можливостями додавати імперативні вставки на 💻;
2) добре структуровані концепції;
3) швидкий білд без проміжних кроків;
4) не 🤮 CMake 🙂

Реальність трохи більш прозаїчна: мова там не QML, а «діалект QML» — семантика значно відрізняється, бо чинні мейнтейнери на QML ніколи й не писали, лол. Імперативні вставки на JS працюють не так, як очікуєш. Дебажити це неможливо. Нема простих способів робити банальні речі, як-от подивитися команди, які при білді запускаються. Думаєте, достатньо написати -v? А ось хєр! у такому режимі Qbs висирає гігатонну логів, які мають бодай-якийсь сенс виключно для розробників самого кьюбса. (Насправді ж треба писати --command-echo-mode command-line 🤕).

Ну а добре структуровані й логічні концепції… постійно стають на заваді! Наприклад, треба мені було задеплоїти разом зі своєю програмою теку з розширеннями QML з самої 💻. Але кьюбс нічого не знає про теки — він оперує тільки файлами, які він називає артефактами. Артефакти позначаються теґами: один артефакт може мати багато різних теґів, а одному теґу можуть належати різноманітні артефакти. Конкретні теґи опрацьовуються певними правилами. Правила містяться у модулях, на які треба додати залежність. Правило завжди має чіткі вхідні й вихідні артефакти. З усього цього Qbs будує граф правил. Але кьюбс ніколи не робить зайвої роботи — це його фішка. Він будує тільки те, що мусить. І все завжди починається з вашого найголовнішого продукту, який також має теґ.

Тобто білд-система дивиться, і така: «Ага, оцей продукт — це артефакт з теґом application. Звідки його взяти?» — і починає шукати правила, які дають на вихід application. Таким правилом є, наприклад, те, що викликає компонувальник. Воно своєю чергою вимагає на вхід якісь артефакти на кшталт obj, staticlibrary і таке інше. Де взяти їх? Ну, obj можна отримати з cpp. Ви зрозуміли, короч. Хоча це все вельми спрощено.

Прикол у тому, що якщо раптом для побудови фінального продукту кьюбсу не треба зачіпати якісь конкретні теґи, то він і не буде. Я так писав модуль для автоматичного збирання залежностей для моїх QML-файлів, додав його у білд — а воно нічого не робить. І зазвичай геть не очевидно, чого саме.

Інша тема, що всі артефакти — це унікальні сутності, навіть якщо фізично вони вказують на одні й ті ж файли. Так, я раніше написав, ніби це тотожні штуки, але не зовсім. Зібрав я, значить, залежності для QML-файлів — це певні ліби з самого кьюта. Є в мене Foo.qml, якому потрібні qlib1 і qlib2, а є Bar.qml, якому потрібні qlib2 й qlib3 — фізично всі ці ліби лежать у теці з кьютом, але для кожного продукту я створюю «віртуальні» артефакти, щоб все це правильно бачила білд-система. Потім я всі ці залежності хочу встановити в цільову теку програми. А ніііііфііііігаааа! 😡 Qbs такий: «ти встановлюєш qlib2, але там вже лежить інший!» — сґітісаI еґґоґ.

Додати до цього всього ду-у-у-уже специфічний спосіб описувати модулі й правила, причому на ES5, практичну неможливість побачити свій проєкт «очима Qbs», бажано візуально, відсутність просторів імен, що ставить хрест на перевикористанні деяких штук у різних проєктах, тяжку взаємодію з єдиним доступним там менеджером пакетів — Conan (як альтернативу радять pkg-config… у 2k25…), а також майже нульові можливості для зневадження проблемних білд-скриптів — і не лишається майже нічого, за що можна було б зачепитися (окрім того факту, що це досі не CMake 😂).

А, і ще сорци хоч і лежать на ґітгабі — але там чисто дзеркало. PR кинути не можна — треба натомість створювати патчсет на кьютовий ґерріт.

Отже, подивилися ми з друганами на все це вкотре й вирішили, що час щось міняти. Але на що саме? Один з нас розпочав аналіз альтернатив, згодом долучився я, і… здається, нам вдалося знайти непогані варіанти. Днями розповім.
Please open Telegram to view this post
VIEW IN TELEGRAM
😁8👍52🔥2🤯1