Графични (desktop) интерфейси
07 януари 2025
GTK
- Rust binding-и към GTK библиотеката
- Главния сайт: https://gtk-rs.org/
- Добър guide за GTK4: https://gtk-rs.org/gtk4-rs/stable/latest/book/
- API документация за GTK4: https://docs.rs/gtk4/
- API документация за GTK3 (unmaintained): https://docs.rs/gtk/
GTK
- Rust binding-и към GTK библиотеката
- Главния сайт: https://gtk-rs.org/
- Добър guide за GTK4: https://gtk-rs.org/gtk4-rs/stable/latest/book/
- API документация за GTK4: https://docs.rs/gtk4/
- API документация за GTK3 (unmaintained): https://docs.rs/gtk/
Вижте презентацията от https://2022.fmi.rust-lang.bg/lectures
GTK
- ✅ Тонове widget-и за каквото ви душа иска
- ✅ Native look and feel, подръжка на accessability
- ✅
GTK_DEBUG=interactive
, има glade за интерфейс - ✅ Guide и обилна документация
GTK
- ✅ Тонове widget-и за каквото ви душа иска
- ✅ Native look and feel, подръжка на accessability
- ✅
GTK_DEBUG=interactive
, има glade за интерфейс - ✅ Guide и обилна документация
- ❌ ООП библиотека - особени абстракции като
IsA<T>
и*Ext
trait-ове - ❌ Голям surface area
- ❌ Вероятно малко досадно да се подкара под windows, macOS
Iced
- https://github.com/iced-rs/iced/
- библиотека изцяло писана на Rust
- различна архитектура - не се регистрират callback функции по widget-ите
- вместо това при интеракция се генерират съобщения
Iced
- библиотеката не е завършена
- но има roadmap и се разработва активно
- някои стандартни widget-и липсват - например таблици
- за някои widget-и има отделни библиотеки от трети лица
Къде се използва?
- има различни малки приложения - https://github.com/iced-rs/awesome-iced
- Pop!_OS правят desktop environment с iced - https://system76.com/cosmic/ (в alpha фаза)
Egui
- не е самостоятелнен framework
- предвиденo е да се интегрира в съществуващи приложения
- изисква интеграция с ОС прозорците и съобщенията от тях (window event loop)
egui_winit_platform
,egui_sdl2_platform
, …
- изисква интеграция с библиотеката за рендериране
egui_wgpu
за WGpu,egui_glow
за OpenGl, …
- съществуват и комбинирани библиотеки
eframe
- официален framework, за използване на Egui за самостоятелни GUI приложенияbevy_egui
,godot_egui
- интеграции с game engines
Retained vs immediate mode
retianed mode
- стандартния стил за GUI библиотеки
- GTK, QT, iced, …
- създава се дърво от widget-и
- widget-ите си държат състояние
- при промяна се модифицират дървото от widget-и или състоянието им и се рендерират наново
Retained vs immediate mode
retianed mode
- използва се за повечето стандартни графични приложения
- по-евтин, защото е мързелив
- правят се сметки и се рендерира нов кадър само когато има промяна
- GUI-то е централния елемент в програмата
- данните обикновенно се държат във widget-ите
- ако има копие на данните извън widget-ите, при промяна трябва да се синхронизират ръчно
Retained vs immediate mode
immediate mode
- популяризиран от библиотеки за (дебъг) UI в игри
- Dear Imgui, egui, …
- няма персистентно дърво от widget-и
- на всеки кадър се извиква функция, която описва всички widget-и
- и същевременно отговаря на интеракциите с тях
Retained vs immediate mode
immediate mode
1
2
3
if ui.button("label").clicked() {
/* handle click */
}
ui.button()
оказва, че трябва да се нарисува бутон.
Функцията не връща widget, ами egui::Response
. Ако същия бутон е бил нарисуван предишния кадър, Response
ще съдържа информация какво се е случило с него:
- дали е бил
.hovered()
- дали е бил
.clicked()
- във всеки случай, интеракцията се обработва на момента, веднага след описване на widget-а
Retained vs immediate mode
immediate mode
1
2
3
4
5
6
ui.horizontal(|ui| {
ui.label("Add new task");
if ui.button("+").clicked() {
/* hanle click */
}
});
- библиотеката трябва да държи някакво състоянието за widget-ите между два кадъра
- например на какви координати е бил нарисуван последно и с какъв размер
- това става полу-прозрачно за потребителя
- за всеки widget се създава персистентен идентификатор
- обикновенно базиран на позицията му в дървото от widget-и
- "втория бутон в първия хоризонтален контейнер в левия страничен панел"
- понякога трябва да се зададе експлицитно
- скритото състояние за всеки widget се държи в egui контекста
Retained vs immediate mode
immediate mode
- README-то на egui в github също има добро обяснение за immediate mode
- https://github.com/emilk/egui/?tab=readme-ov-file#why-immediate-mode