luna MIT License
git clone https://git.paganlinux.eu/luna.git
| Name↕ | Size↕ | Last change↕ | |
|---|---|---|---|
| apps/ | 10 godz. temu | ||
| assets/ | 1 dni temu | ||
| crates/ | 10 godz. temu | ||
| de/ | 10 godz. temu | ||
| examples/ | 1 dni temu | ||
| packaging/ | 1 dni temu | ||
| scripts/ | 1 dni temu | ||
| templates/ | 15 dni temu | ||
| tools/ | 15 dni temu | ||
| .gitignore | 42 B | 15 dni temu | |
| Cargo.lock | 0.0 KB | 1 dni temu | |
| Cargo.toml | 0.0 KB | 1 dni temu | |
| LICENSE | 0.0 KB | 15 dni temu | |
| README.md | 0.0 KB | 11 dni temu | |
| rust-toolchain.toml | 66 B | 15 dni temu |
libLuna
English — A lightweight, pure-Rust GUI toolkit: a from-scratch alternative to GTK4 + libadwaita, built for the Luna desktop.
Polski — Lekki zestaw narzędzi GUI w czystym Rust: alternatywa od zera dla GTK4 + libadwaita, tworzona dla środowiska Luna.

Status: M0 działające — fundament, rysowanie, okno Wayland oraz wielojęzyczność i przełączanie wyglądu (tryb jasny/ciemny/auto, kolory akcentu, metryki kontrolek). Repozytorium: https://github.com/mijsys/libLuna.
Why libLuna exists
libLuna exists because building a desktop the way we want it — small, fast, memory-safe and coherent — is awkward with the options that already exist.
- GTK4 + libadwaita is capable but heavy. It drags in the GObject/glib runtime, a large C dependency tree and manual reference counting. For a lightweight desktop that is more machinery than the job needs.
- The alternatives are no better fit. Qt bindings are enormous; most Rust-native toolkits (egui, iced, …) are render- or immediate-mode oriented and do not model desktop-shell chrome — client-side-decorated header bars, sidebars, path bars, tabs, popovers — the way libadwaita does.
- We want one stack, in pure Rust. No GObject, no glib, no GTK: just Rust, a scene graph and a CPU/Wayland backend, with predictable performance and a small binary.
- We want the looks to be swappable. Appearance is defined by design tokens — colors and control geometry — so a theme (or a future installed style file) can reshape the UI without touching widget code.
- We are building a desktop, not just a widget demo. libLuna is the UI foundation for the Luna environment (Wayland compositor Selene), recreating the GTK4/libadwaita look and idioms without the GTK/Qt bloat.
In short: libLuna is a deliberately small toolkit that gives Luna a fast, memory-safe, cohesive UI layer it fully controls — written in the language we already build the rest of the system in.
Dlaczego powstała libLuna
libLuna powstała, bo zbudowanie pulpitu tak, jak chcemy — małego, szybkiego, bezpiecznego pamięciowo i spójnego — jest niewygodne przy dostępnych obecnie opcjach.
- GTK4 + libadwaita jest możne, ale ciężkie. Wciąga runtime GObject/glib, duże drzewo zależności w C i ręczne liczenie referencji. Dla lekkiego pulpitu to więcej maszynerii, niż trzeba.
- Alternatywy nie pasują lepiej. Wiązania do Qt są ogromne; większość natywnych dla Rusta toolkitów (egui, iced, …) jest nastawiona na render/immediate-mode i nie odwzorowuje „chrome” pulpitu — pasków tytułu z CSD, pasków bocznych, okruszków ścieżki, zakładek, popoverów — tak jak robi to libadwaita.
- Chcemy jeden stos, w czystym Rust. Bez GObject, bez glib, bez GTK: sam Rust, graf sceny i backend CPU/Wayland, z przewidywalną wydajnością i małym rozmiarem binarki.
- Chcemy wymienny wygląd. Wygląd opisują tokeny — kolory oraz geometria kontrolek — więc motyw (a w przyszłości instalowany plik stylu) może zmienić UI bez dotykania kodu widgetów.
- Budujemy pulpit, nie tylko demo widgetów. libLuna to fundament UI środowiska Luna (kompozytor Wayland Selene), odtwarzający wygląd i idiomy GTK4/libadwaita — bez balastu GTK/Qt.
Krótko: libLuna to celowo mały toolkit, który daje Lunie szybką, bezpieczną pamięciowo i spójną warstwę UI, w pełni przez nas kontrolowaną — napisaną w języku, w którym budujemy resztę systemu.
Nazewnictwo
Wzorem GTK / GNOME / Mutter (i Qt / KDE / KWin) rozdzielamy trzy warstwy:
| Warstwa | Odpowiednik GNOME | Odpowiednik KDE | Nasza nazwa |
|---|---|---|---|
| Toolkit (biblioteka) | GTK | Qt | libLuna |
| Środowisko / powłoka | GNOME | KDE Plasma | Luna |
| Kompozytor Wayland | Mutter | KWin | Selene |
To repozytorium to libLuna (toolkit). Środowisko Luna (powłoka, panele, aplikacje) i kompozytor Selene buduje się na nim.
Decyzje projektowe
- Język: czysty Rust — bez GObject/glib i bez GTK/Qt. Stąd lekkość i bezpieczeństwo
pamięci; integracja z powłoką odbywa się przez standardowy Wayland (
xdg-shell, a dla paneliwlr-layer-shell). - Rysowanie: własny stos — graf sceny + backend CPU (tiny-skia + fontdue). Bez Cairo/Pango.
- Wielojęzyczność: własna, bez gettext — kluczem jest angielski napis, więc brak
tłumaczenia degraduje się łagodnie do angielskiego. Każdy język to osobny plik
i18n/<kod>.lang; wbudowane: pl, en, de, a kolejne można dołożyć w runtime bez rekompilacji (katalogi~/.config/luna/i18n,~/.local/share/luna/i18n,/usr/share/luna/i18n). - Kompozytor docelowy: Selene (Wayland) — jako zwykły klient
xdg-shell/wlr-layer-shell.
Struktura repozytorium
libluna/
crates/
libluna/ # fasada: jedno wejście (core + render + platform + widgets + i18n) + prelude
libluna-core/ # geometria, kolor, skala, zdarzenia, tokeny motywu, ustawienia wyglądu
libluna-i18n/ # wielojęzyczność: każdy język w pliku i18n/<kod>.lang + przełączanie w runtime
libluna-render/ # graf sceny + backend software (tiny-skia + fontdue)
libluna-platform/ # Wayland: xdg-shell (CSD), wl_shm, wejście, pętla zdarzeń, motyw w Frame
libluna-widgets/ # widgety: ViewSwitcher, NavList, Menu, Button, Switch, Slider, DropDown, HeaderBar, TabBar/TabView, BottomSheet, Pager, PathBar, SearchEntry, ItemView, ScrollView, Stepper, CheckButton, RadioGroup, Card, ActionRow
apps/
luna-demo/ # demo aplikacji środowiska Luna; też render offline do PNG
de/ # środowisko graficzne Luna
README.md # opis Selene (kompozytor) + nazewnictwo
selene/ # kompozytor Wayland (bez smithay: wayland-server + własna pętla)
templates/
minimal-app/ # szablon startowy aplikacji
tools/
libluna-new.sh # scaffolder: generuje gotowy projekt aplikacji
docs/ # architektura, roadmap, zrzuty ekranu
Mapowanie pojęć GTK/GDK/Gsk/libadwaita → libLuna: docs/architecture.md.
Plan dalszej pracy: docs/roadmap.md.
Budowanie i uruchamianie
Wymagany stabilny toolchain Rust. Jeśli go brak:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo build --workspace
cargo test --workspace
Okno z demem (wymaga kompozytora Wayland, np. Selene):
cargo run -p luna-demo
Podgląd bez kompozytora — render do PNG (język, motyw i akcent do wyboru):
cargo run -p luna-demo --bin render -- --lang pl docs/images/settings-light.png
cargo run -p luna-demo --bin render -- --no-sidebar --sidebar-width 340 /tmp/out.png
cargo run -p luna-demo --bin render -- --dark --accent purple --lang de docs/images/settings-de-dark.png
Demo interaktywne bez kompozytora (headless)
Logika interakcji jest niezależna od Waylanda (bierze zdarzenia + ustawienia), więc da się
ją uruchomić bez okna. „Driver” przepuszcza prawdziwe zdarzenia (klik w segment motywu,
w kropkę akcentu, w pozycję nawigacji, w przełącznik widoku, w ikonę ◧, przeciąganie
krawędzi) przez tę samą funkcję handle_events i renderuje klatki:
cargo run -p luna-demo --bin simulate # → docs/images/demo-step-*.png + demo-montage.png
cargo test -p luna-demo --test interaction # te same interakcje jako asercje

Instalacja środowiska na PC (testowo / na stałe)
scripts/install.sh buduje binarki w trybie release i instaluje środowisko Luna
(kompozytor selene, powłoka luna-shell, sesja luna-session, demo, tłumaczenia, motywy,
wpis sesji Wayland i ikonę sesji):
# instalacja testowa do katalogu (bez ruszania systemu) — nic nie wymaga uprawnień
./scripts/install.sh --destdir /tmp/luna-test --prefix /usr
# podgląd planu bez zmian
./scripts/install.sh --dry-run
# instalacja systemowa
sudo ./scripts/install.sh --prefix /usr
# usunięcie
sudo ./scripts/install.sh --prefix /usr --uninstall
Po instalacji sesja „Luna” pojawia się w menedżerze logowania (share/wayland-sessions/selene.desktop),
z ikoną Luna (share/icons/hicolor/.../apps/luna.svg + PNG w kilku rozmiarach oraz pixmaps/luna.png,
rysowanymi z assets/branding/luna.svg).
Na sprzęcie Selene przejmuje ekran przez DRM/KMS — trzeba wylogować bieżący pulpit (wolny
master DRM) i mieć dostęp do /dev/input (grupa input) dla wejścia. Testowo, obok działającej
sesji, można uruchomić SELENE_BACKEND=nested selene (okno na obecnym pulpicie) i podłączyć
luna-shell. Gdy sesja od razu wraca do menedżera logowania, sprawdź XDG_RUNTIME_DIR —
Selene i luna-session wybierają go awaryjnie same. Szczegóły: de/README.md.
Budowanie własnej aplikacji na libLunie
Najszybsza droga to fasada libluna — jedna zależność zamiast czterech. Trzy sposoby:
[dependencies]
libluna = { path = "../libluna/crates/libluna" } # monorepo / sąsiedni katalog
# libluna = { git = "https://github.com/mijsys/libLuna.git" } # z repozytorium
# libluna = "0.0.1" # z rejestru (docelowo)
W kodzie wystarczy prelude:
use libluna::prelude::*;
fn main() -> Result<(), Box<dyn std::error::Error>> {
set_locale(Locale::from_env());
let config = AppConfig::new("Moja apka").initial_size(800, 600);
run(config, |frame: &mut Frame| {
// frame.events — zdarzenia; frame.scene — graf sceny;
// frame.theme — motyw; frame.measure_text(...) — pomiar tekstu
})
}
Scaffolder (najszybciej)
./tools/libluna-new.sh ~/projekty/moja-apka
cd ~/projekty/moja-apka && cargo run
Skrypt tworzy projekt z poprawną ścieżką do libLuny. Szablon: templates/minimal-app.
Działający przykład
cargo run -p libluna --example minimal
Uwaga: na tym etapie (przed M2) aplikacja wypełnia graf sceny ręcznie. Gdy wejdą layout i drzewo widgetów, ten sam
run(...)przyjmie deklaratywne drzewo — kod aplikacji stanie się jeszcze krótszy.
Sterowanie w demo
- Mysz — kliknij ikonę
◧w HeaderBarze, aby zwinąć/rozwinąć pasek boczny (ikona zmienia się w▭),☰aby otworzyć menu (zamyka się klikiem poza panelem), lub kontrolkę języka (DropDown). Przycisk „Opcje ▾” otwiera popover opcji (Stepperrozmiaru ikon,RadioGroupsortowania,CheckButtonukrytych plików). Z menu☰→ „Styl” wybierzesz styl z pliku (natychmiast stosowany i zapisywany), a☰→ „O aplikacji” otwiera dolny panel (BottomSheetz karuzelą stronPageri polem tekstowymEntry— klik = fokus, wpisywanie), zamykany klikiem w tło, przyciskiem✕lub przeciągnięciem w dół. W karcie Pliki kliknij element okruszków (nawigacja „w górę”), pole wyszukiwania (fokus) lub plik/katalog (zaznaczenie); przełącznikLista | Siatkazmienia trybItemView, a rolka/przeciąganie paska przewija listę. Wpisany tekst w polu wyszukiwania filtruje elementy; gdy nic nie pasuje, pojawia się ekran stanu (StatusPage) z przyciskiem „Wyczyść”. Zmiana koloru akcentu pokazujeToastz akcją „Cofnij”, która przywraca poprzedni akcent (klik w treść powiadomienia zamyka je bez cofania). Klikaj segmentyJasny | Ciemny | Auto, kropki koloru akcentu, przełączniki OPCJA A / Pasek dolny / Pasek boczny i przeciągaj suwak głośności oraz krawędź paska bocznego (150–460 px). Kontrolki okna[—][□][✕]działają (minimalizacja/maksymalizacja/zamknięcie przez warstwę platformy). - Klawiatura — skróty:
l= jasny/ciemny,a= następny akcent,g= następny język,b= pokaż/ukryj pasek dolny,s= pokaż/ukryj pasek boczny,v= widok,o= dolny panel („O aplikacji”),Esc= zamknij. - Zmiany wyglądu są zapisywane do
~/.config/luna/theme.confi wczytywane przy starcie. - Tryb systemowy (
Auto) czyta zmiennąLUNA_SYSTEM_DARK=1(docelowo portal D-Bus).
Własny wygląd (motywy)
Wygląd libLuny to tokeny, nie kod widgetów — dlatego „odejście od Adwaty” to głównie podmiana zestawu tokenów, a nie przepisywanie komponentów. Wygląd opisują trzy warstwy:
- Wariant —
Ciemny / Jasny / Auto(ThemePreference). - Kolor akcentu (
Accent, 9 kolorów). - Geometria kontrolek (
Metrics) — rozmiary i paddingi widgetów.
Wszystkie tokeny (odstępy, promienie, typografia, metryki kontrolek, paleta) żyją
w Theme w libluna-core. Zmiana wariantu i akcentu jest natychmiastowa, a wybór zapisuje się
w ~/.config/luna/theme.conf.
Component metrics
Rozmiary i paddingi kontrolek nie są już stałymi w widgetach, lecz tokenami
(Theme::metrics) podzielonymi na sekcje per widget: headerbar, button, switch,
slider, dropdown, menu, nav, segmented, tabs, sheet, pager, pathbar, entry,
itemview, scrollview, stepper, check, radio, card, row, toast, status. Dzięki temu wygląd steruje także
geometrią, nie tylko kolorami — np. theme.metrics.switch.width albo
theme.metrics.headerbar.height. Widgety czytają te wartości w paint/layout, więc
przyszły, instalowany styl może zmienić np. wysokość paska tytułu czy rozmiar przełącznika
bez dotykania kodu.
Style instalowane z plików (jak w GNOME/KDE)
Wygląd można wybrać nie tylko enumatorem w kodzie, lecz stylem zainstalowanym jako plik.
Style to pliki *.theme w katalogach (kolejność = priorytet):
~/.config/luna/themes, ~/.local/share/luna/themes, /usr/share/luna/themes.
Format jest liniowy (klucz = wartość, # = komentarz), z kropkowymi kluczami:
__name__ = Nord # nazwa w UI
appearance = dark # light | dark (wybiera bazową paletę)
colors.card_bg = #3b4252
colors.text = #eceff4
accent = teal
radius.small = 5
metrics.button.height = 36
metrics.headerbar.height = 48
Klucze pokrywają colors.*, spacing.*, radius.*, typography.*.size i metrics.*
(np. metrics.switch.width) — styl steruje więc nie tylko kolorami, ale i geometrią.
Nieznane klucze są ignorowane (zgodność wprzód). Wczytuje/nakłada to
libluna_core::theme_file (ThemePatch), a wybrany styl zapisuje się w theme.conf
(style = <nazwa>). Przykłady: examples/luna/themes/nord.theme, paper.theme.
Podgląd (headless) tego samego okna w stylach:
cargo run -p luna-demo --bin render -- --theme examples/luna/themes/nord.theme docs/images/settings-nord.png
cargo run -p luna-demo --bin layout -- --theme examples/luna/themes/nord.theme --out docs/images/layout-nord.png
Do zrobienia pozostaje okno podglądu na żywo wewnątrz aplikacji (miniatura aktualizowana przy
przewijaniu listy). Sam wybór stylu działa już w demo: menu ☰ → „Styl” otwiera listę
(„Domyślny” + style z plików), a wybór jest natychmiast stosowany i zapisywany w theme.conf.
Headlessowy podgląd (montaż motywów) to cargo run -p luna-demo --bin styles →
docs/images/styles.png. W headless demo/testach katalog ze stylami wskazuje LUNA_THEMES_DIR.
Co jeszcze decyduje o „looku GTK4”
Tokeny zmieniają kolory i geometrię kontrolek, ale o tym, czy okno „wygląda jak z GTK4”,
decyduje też chrome okna: umiejscowienie kontrolek ([—][□][✕]), wyrównanie tytułu,
zaokrąglone narożniki, cień. To warstwa widgetu HeaderBar (opcje ControlsSide,
TitleAlign, ControlsLayout) — dzięki temu stronę kontrolek czy wyrównanie tytułu można
zmienić bez przepisywania aplikacji. Rozmiar samych kontrolek okna jest już tokenem
(theme.metrics.headerbar.control).
Dodawanie i edycja języków
Każdy język to jeden plik crates/libluna-i18n/i18n/<kod>.lang. Format:
__name__ = Français # natywna nazwa języka w UI (opcjonalne)
Appearance = Apparence # klucz (angielski) = tłumaczenie
# linie zaczynające się od # to komentarze
- Wbudowane pliki (
pl,en,de) są wkompilowane przezinclude_str!. - Kolejne języki wystarczy wrzucić jako
<kod>.langdo~/.config/luna/i18n,~/.local/share/luna/i18nlub/usr/share/luna/i18n— zostaną doładowane przy starcie (nadpisują wbudowane; brakujące klucze spadają do angielskiego). - Demo przełącza się między wszystkimi wykrytymi językami (klawisz
glub klik w „Język”).
Przykładowy, kompletny plik francuski jest w examples/luna/i18n/fr.lang:
XDG_CONFIG_HOME="$PWD/examples" cargo run -p luna-demo --bin render -- --lang fr /tmp/fr.png
Co już działa (M0 + i18n/wygląd)
libluna-core:Point/Size/Rect/Insets,Color(sRGB, hex),Scale, zdarzenia, tokeny motywu (Spacing,Radius,Typography), metryki kontrolek (Metrics) oraz ustawienia wyglądu (ThemePreference,Accent,ThemeSettingsz trwałością i rozwiązywaniemlight/dark), a także style instalowane z plików (theme_file:ThemePatch, skanowanie katalogówavailable_themes()). Animacje:motion(Easing,lerp,Animation) — matematyka ruchu i animowany skalar, bez stanu w widgetach.libluna-i18n:Locale(zLANG/LC_*),Catalog,Translations, globalnetr/set_locale, makrot!z podstawianiem argumentów, języki z osobnych plikówi18n/<kod>.lang(wbudowane) oraz doładowywane w runtime z katalogów;languages()ilanguage_name().libluna-render: graf sceny (prostokąty, zaokrąglenia, obramowania, linie, clip, tekst, obrazyScene::image/ImageData) i rasteryzator CPU z antyaliasingiem; tekst przezfontdue(font Adwaita Sans).libluna-platform: oknoxdg-shellz CSD, buforwl_shm, pętlacalloop, zdarzenia wejścia (wskaźnik, klawiatura, scroll) wFrame, odświeżanie na żądanie, zarządzanie motywem przezFrame::set_preference/set_accent(zapis + natychmiastowe przerysowanie).Frame::close/minimize/toggle_maximizeto realne akcje okna (xdg_toplevel). Klatki animacji: aplikacja czytaFrame::delta_time()i wołaFrame::request_frame(), dopóki trwa animacja — okno odświeża się wtedy płynnie (~60 Hz), a bez tego tylko na zdarzenia.libluna-widgets: widgety wielokrotnego użycia w modelu immediate —ViewSwitcher(segmentowy),NavList(menu nawigacji z sekcjami),Menu(popover☰),Button(z wariantami i chevronem),Switch,Slider,DropDown(z rozwinięciem przezMenu),HeaderBar(pasek tytułu: tytuł, kontrolki okna, obszar na treść),TabBar/TabView(pasek zakładek i model stron: wybór, dodawanie, zamykanie; przy przepełnieniu przewijany z przyciskami na krawędziach),BottomSheet(dolny panel modalny z „grabberem”, przeciąganiem i zamykaniem),Pager(karuzela stron z kropkami),PathBar(okruszki z separatorem›, wskaźnikiem▾i zwijaniem do…),Entry(pole tekstowe: kursor, edycja, zaznaczanie i schowek —select_all/copy/cut/paste, Shift+strzałki/Ctrl+A, opcjonalna ikona wiodąca i czyszczenie; to samo wTextView) — zSearchEntryjako jego wyszukiwarkową nakładką (lupka + czyszczenie),ItemView(pliki/katalogi w siatce lub liście, z zaznaczaniem i przewijaniem) iScrollView(pionowe przewijanie: rolka + „kciuk”) orazStepper,CheckButtoniRadioGroup(krokowiec, pole wyboru, wybór jednokrotny), a takżeCard(karta z nagłówkiem),ActionRow(wiersz ustawień),Toast(powiadomienie nakładkowe z akcją, np. „Cofnij”),StatusPage(ekran stanu: ikona, tytuł, opis, akcja — używany jako „pusty stan” listy),Spinner(wskaźnik zajętości — obracający się łuk),Tooltip(dymek podpowiedzi) iBanner(pasek komunikatu info/ostrzeżenie/błąd z akcjami) oraz wspólnyPaintCtx.libluna-widgets— galeria w duchu libadwaita (dalszy zestaw):Avatar,ShortcutLabel,ToggleGroup,SplitButton,Bin; rodzina wierszyRow(switch/combo/expander/entry/password/spin/slider/button/nav) orazPreferencesGroup/PreferencesPage;Dialog,AlertDialog,AboutDialog,ShortcutsDialog,PreferencesDialog; nawigacjaNavigationView,NavigationSplitView,OverlaySplitView,Sidebar(Carousel= aliasPager); pomocnikiToolbarView,WindowTitle,Clamp,WrapBox,BreakpointBin,ButtonContent.libluna-widgets— galeria GTK4 (kolejny zestaw): prezentacjaLabel,Separator,ProgressBar,LevelBar,Frame,Revealer,Overlay,AspectFrame; przyciskiToggleButton,LinkButton,ColorButton; pola specjalnePasswordEntry(maskowanie + podgląd „oko”) iEditableLabel; konteneryCenterBox,Grid,Fixed,Paned(przeciągany separator),Stack,ActionBar,PopoverMenuBar; orazMenuButton,SearchBar,Expander,Statusbar,Calendar,Image(ikony wektorowe),TextView(pole wielolinijkowe),Popover(generyczny),ColumnView(tabela),Assistant(kreator kroków),Scrollbar/Adjustment(przewijanie w obu osiach),ColorChooser(paleta),FlowBox(zawijająca siatka z wyborem),SpinButton(pole liczbowe),EmojiChooser(siatka emoji),NavigationRail(kompaktowa szyna nawigacji),Viewport,WindowHandle(obszar chwytu okna); aliasyScrolledWindow=ScrollView,StackSwitcher=ViewSwitcher,Notebook=TabView,ListBox=NavList. Animacje wcielone w widgety: przejściaStack(slide/fade przezStackTransition), płynnyRevealer,Toast(wjazd + fade),BottomSheet(wysuwanie),Pager(animowane przyciąganie do strony) — sterowane z aplikacji przezadvance(dt, …).libluna-widgets::layout: dwuprzebiegowy układ (retencyjne drzewomeasure/allocate) — [Node] (VBox/HBox,Padding,Expanded,Center,Spacer,Label,Fixed),ConstraintsiLayout. Liście pochłaniają nadmiar (Expanded/Spacer),Labelmierzy się realną czcionką.luna-demo:HeaderBarjako widget (tytuł +[—][□][✕]po prawej + treść:◧,+, „Opcje ▾”,☰); karty i wiersze ustawień rysowane widgetami (Card,ActionRow); popover☰, chowany i rozciągany (drag) panel boczny (NavList), chowany pasek dolny, wybór motywu/widoku (ViewSwitcher),Switch,Slider,DropDown, zakładki (TabBar+TabView) oraz dolny panel (BottomSheetz karuzeląPager, otwierany z menu☰→ „O aplikacji”), a także kartę Pliki (PathBar+SearchEntry+ItemView— przełącznik Widok: Lista | Siatka zmienia tryb widoku elementów; wyszukiwanie filtruje elementy, a brak wyników pokazujeStatusPage„Brak wyników” z akcją „Wyczyść”). Zmiana koloru akcentu wyświetlaToastz akcją „Cofnij”.- Rozmiary i paddingi kontrolek są tokenami (
Theme::metrics), więc geometria jest tak samo „stylowalna” jak kolory — nie ma już stałych typów w widgetach (HeaderBar::HEIGHT,Switch::WIDTH,Button::HEIGHT…).
Układ (measure/allocate)
Prostokąty można liczyć ręcznie, ale libluna-widgets::layout
daje retencyjne drzewo: aplikacja składa [Node], silnik robi pomiar (measure, względem
Constraints min/max) i rozmieszczenie (allocate) — dwuprzebiegowo, jak w klasycznych
toolkitach. Kontenery: VBox/HBox (odstęp gap), Padding, Expanded/Spacer (pochłaniają
nadmiar wzdłuż osi), Center (naturalny rozmiar wyśrodkowany). Liściami są Fixed, Label
(mierzy się czcionką) i Spacer; Node::visit pozwala obejść drzewo z prostokątami, a
Layout::fit zwraca prostokąty liści w kolejności DFS. Demo Ustawień używa już tego silnika
(karty i ich wiersze w ui::layout).
Minimalny przykład (apps/luna-demo/src/bin/layout.rs) buduje kartę ustawień wyłącznie
z drzewa i renderuje ją headless:
cargo run -p luna-demo --bin layout # → docs/images/layout.png
Zrzuty ekranu
Jasny i ciemny motyw (Luna) oraz wersja niemiecka z fioletowym akcentem i francuska z pliku doładowanego w runtime:

Style instalowane z plików (examples/luna/themes/nord.theme, paper.theme) — kolor i geometria:

Podgląd kilku motywów (headless, cargo run -p luna-demo --bin styles) — ten sam realny
interfejs w każdym stylu:

Nowe widgety — Banner, Spinner, Tooltip (cargo run -p luna-demo --bin widgets):

Pełna galeria nowych widgetów libLuny (cz. 5–12) — kontenery, tabele, kalendarz, chooser’y,
kreator kroków, pasek stanu itd. (cargo run -p luna-demo --bin gallery):

Przebieg interakcji (headless simulate) — m.in. menu ☰, dolny panel, powiadomienie (Toast)
karta 12 i ekran stanu („Brak wyników”) klatka 14:

Karta ustawień złożona z drzewa układu (measure/allocate):

Motywacja i kontekst
Środowisko Luna (kompozytor Selene) ma docelowo zastąpić GTK4/libadwaita w aplikacjach
i ujednolicić warstwę UI w czystym Rust. Bazą jest tu libLuna; dotychczasowy świat KartONDE
(powłoka karton-shell, aplikacje karton-settings/karton-files) migruje na libLunę.
Licencja
MIT
- 79d885e widgety: scroll/overflow w TabBar (przewijanie + przyciski na krawędziach)
- e27c7d7 widgety: Spinner, Tooltip, Banner + tokeny metryk
- 3a3cdab style: podgląd motywów (bin styles) — montaż realnego UI w kilku stylach
- f69143f style: wybór stylu z UI (menu ☰ → „Styl")
- 02466d3 style: instalowane z plików (theme_file) + trwały wybór stylu
- 3c2afd2 layout: dwuprzebiegowy układ measure/allocate (retencyjne drzewo)
- 9980997 widgety: Entry (pole tekstowe) i SearchEntry na jego bazie
- 797a833 diagnostyka: komunikaty asercji i logów po angielsku
- d636603 widgety: Toast + StatusPage; demo: powiadomienie i pusty stan listy
- 45c3fa8 widgety: Card + ActionRow; demo korzysta z nich dla kart i wierszy
- 3721027 widgety: Stepper, CheckButton, RadioGroup + popover Opcje
- 9e898ed widgety: ItemView, ScrollView, PathBar, SearchEntry + karta Pliki
- cc6e3a9 libLuna: lekki toolkit GUI w czystym Rust (M0)
- 6a66c74 Initial commit