diff options
| author | Adam Malczewski <[email protected]> | 2026-06-14 16:00:49 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-14 16:00:49 +0900 |
| commit | 41abc47bfb4a5098bff611e3e241d2b63788cbec (patch) | |
| tree | 9df638f56c16c2cc6cf9dac0648cb50687ff0929 /packages/kernel/src/ui_substrate.cpp | |
| parent | 89c40575c353dfd3c9fcaf60d2bd45d3fa2b6792 (diff) | |
| download | unbox-41abc47bfb4a5098bff611e3e241d2b63788cbec.tar.gz unbox-41abc47bfb4a5098bff611e3e241d2b63788cbec.zip | |
kernel: add request_frames() frame callback + UiSurface::transition_timing()
Two additive primitives for C++-driven, RCSS-tunable animation:
- Host::request_frames(cb) -> FrameRequest: a per-frame callback (RAII handle)
run before tick_all each frame; the kernel schedules frames continuously while
>=1 request is alive and stops at rest. Fills the missing animation timer.
- UiSurface::transition_timing(element_id, property): reads the RCSS-authored
transition duration + easing, returning RmlUi's tween wrapped as a pure
std::function (no RmlUi types cross the contract) so an extension can drive its
own animation with hot-reloadable, designer-tunable timing/easing.
Diffstat (limited to 'packages/kernel/src/ui_substrate.cpp')
| -rw-r--r-- | packages/kernel/src/ui_substrate.cpp | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/packages/kernel/src/ui_substrate.cpp b/packages/kernel/src/ui_substrate.cpp index 4c9efe8..9b9593d 100644 --- a/packages/kernel/src/ui_substrate.cpp +++ b/packages/kernel/src/ui_substrate.cpp @@ -3,6 +3,7 @@ #include "file_watcher.hpp" #include "rmlui_renderer_gl3.h" +#include <RmlUi/Core/Animation.h> // Transition / TransitionList / Tween #include <RmlUi/Core/Context.h> #include <RmlUi/Core/Core.h> #include <RmlUi/Core/DataModelHandle.h> @@ -12,7 +13,10 @@ #include <RmlUi/Core/Event.h> #include <RmlUi/Core/Factory.h> #include <RmlUi/Core/ID.h> +#include <RmlUi/Core/Property.h> +#include <RmlUi/Core/StyleSheetSpecification.h> // GetPropertyId #include <RmlUi/Core/SystemInterface.h> +#include <RmlUi/Core/Tween.h> #include <RmlUi/Core/Variant.h> // The kernel owns GL; system EGL/GLES headers are allowed here (same as the @@ -2150,6 +2154,63 @@ void SurfaceHandle::dirty() { } } +auto SurfaceHandle::transition_timing(std::string_view element_id, std::string_view property) const + -> std::optional<TransitionTiming> { + const Surface& s = *surface_; + if (s.document == nullptr) { + return std::nullopt; // not loaded yet => no computed values + } + Rml::Element* el = s.document->GetElementById(Rml::String(element_id)); + if (el == nullptr) { + return std::nullopt; + } + // The computed `transition` property: a TransitionList (none/all + entries). + const Rml::Property* prop = el->GetProperty(Rml::PropertyId::Transition); + if (prop == nullptr) { + return std::nullopt; + } + const Rml::TransitionList list = prop->Get<Rml::TransitionList>(); + if (list.none) { + return std::nullopt; + } + + // Resolve the requested property name (e.g. "transform") to RmlUi's id, then + // find the matching per-property transition. An `all` transition applies to + // every property and serves as the fallback if no exact entry exists; an + // exact entry wins over `all`. + const Rml::PropertyId want = Rml::StyleSheetSpecification::GetPropertyId(Rml::String(property)); + const Rml::Transition* match = nullptr; + if (want != Rml::PropertyId::Invalid) { + for (const Rml::Transition& t : list.transitions) { + if (t.id == want) { + match = &t; + break; + } + } + } + Rml::Tween tween; + double duration = 0.0; + double delay = 0.0; + if (match != nullptr) { + tween = match->tween; + duration = static_cast<double>(match->duration); + delay = static_cast<double>(match->delay); + } else if (list.all && !list.transitions.empty()) { + // `all foo 0.2s ease` parses to a single entry flagged all=true; reuse + // its timing/tween for the requested property. + const Rml::Transition& t = list.transitions.front(); + tween = t.tween; + duration = static_cast<double>(t.duration); + delay = static_cast<double>(t.delay); + } else { + return std::nullopt; + } + + // Wrap RmlUi's Tween BY VALUE — Tween::operator()(float) is the evaluator; + // capturing it keeps RmlUi types out of the contract entirely. + return TransitionTiming{duration, delay, [tween](float t) { return tween(t); }}; +} + // ---- PreviewHandle (public Preview impl) ------------------------------------ PreviewHandle::~PreviewHandle() { substrate_->impl_->destroy_preview(state_); } |
