Expand description
Safe Rust bindings to the Noesis GUI native SDK, a XAML-based UI engine, wrapped here by a hand-written C ABI over opaque, reference-counted handles.
The crate is renderer-agnostic: it builds UI trees, drives input, and ticks
the layout/animation engine, but leaves drawing to you through the
render_device::RenderDevice trait. A ready-made Bevy/wgpu integration
lives in the sibling crate noesis_bevy.
§Getting started
The lifecycle is process-wide: call init exactly once at startup and
shutdown once at exit, after every Noesis handle has been dropped. In
between, a typical session looks like:
- Install an asset source with
xaml_provider::set_xaml_provider(plus optional font and texture providers). - Build a UI root:
view::FrameworkElement::loadfrom a URI, orview::FrameworkElement::parsefrom an in-memory XAML string. - Wrap it in a
view::Viewwithview::View::create, then feed it the surface size, input events, and per-frame time updates. - Render the view through your
render_device::RenderDevice.
For a quick import of the types most code reaches for, glob the prelude.
§Setup
Set NOESIS_SDK_DIR to the extracted Noesis Native SDK 3.2.13 root (the
directory containing Include/ and Bin/). See README.md.
§Thread affinity
Noesis objects are thread-affine: the engine expects every method on a
given object (and on the view::View that owns it) to be called from the
one thread that drives that view. The owning handle types in this crate
(geometries, brushes, transforms, commands, bindings, the RAII registration
guards, etc.) therefore implement Send but deliberately not Sync:
Sendis sound.Noesis::BaseRefCounted::mRefCountis anAtomicInteger, so the-1release performed byDropis safe on any thread. Ownership of a handle may be moved to whichever thread owns the Noesis view, after which all calls happen on that thread.Syncis unsound. Many&selfmethods call into Noesis (FFI reads, and some lazily mutate engine state, e.g. resource-dictionary or collection getters). Sharing a&handleacross threads would let two threads invoke those concurrently on a thread-affine engine, which races.
Callers must invoke Noesis methods only from the view’s thread. SAFETY
comments on the individual unsafe impl Send blocks point back here rather
than restating this contract. (The render-device trait is the exception:
a user render_device::RenderDevice impl must be Send + Sync because
Noesis may call its trampolines from a dedicated render thread. That bound
is on the trait, not on these owning handles.)
Modules§
- animation
- Code-built animation & timing: construct
Storyboards, the common animation classes (DoubleAnimation/ColorAnimation/ThicknessAnimation/PointAnimation), their key-frame variants, and the easing-function family from Rust, then run them off theViewclock. - binding
- Data-binding bridge: drive XAML from Rust-owned data.
- brushes
- Code-built brushes and effects: construct
Brush/Effectobjects from Rust and paint elements with them without authoring XAML. - classes
- Register Rust-backed XAML classes.
- collection_
view ICollectionViewcurrent-item navigation.- commands
ICommandfrom Rust: let XAMLCommand="{Binding ...}"invoke Rust logic.- converters
- Rust value converters for data binding.
- diagnostics
- Diagnostics: error / assert handlers and memory-usage queries.
- drawing
- Immediate-mode drawing via
DrawingContext. - element_
tree - Code-side element-tree construction: build and mutate panel trees and
Gridrow/column definitions from Rust. - events
- Subscribe Rust callbacks to Noesis routed events.
- font_
provider - Rust-side
FontProvidertrait +set_font_providerregistration. Mirrorscrate::xaml_provider: a boxed trait object is handed to the C++RustFontProvidersubclass via a vtable of trampolines; the returnedRegisteredguard owns both the boxed impl and the C++ provider handle. - formatted_
text - Code-built
FormattedTextmeasurement / layout: measure a string in a given font without authoring XAML or building aTextBlock. - geometry
- Code-built geometry object model. Construct
Geometryobjects from Rust without authoring XAML:StreamGeometry,PathGeometry(figures + segments), the primitiveEllipse/Rectangle/Linegeometries,CombinedGeometry, andGeometryGroup. - gui
- Thin wrappers around the top-level
Noesis::GUI::*helpers that don’t fit into the provider / view / render-device modules. - imaging
- Code-built
ImageSource/BitmapSourcefamily: constructCroppedBitmap,TextureSource,BitmapImage, andDynamicTextureSourceobjects from Rust without authoring XAML. - input
- Input: keyboard/focus enums, input gestures and bindings, and the
FocusManager/KeyboardNavigationstatic surfaces. - integration
- System integration callbacks from
NsGui/IntegrationAPI.h(namespaceNoesis::GUI). These are process-global host hooks (not per-view) that let the host react to engine requests: update the OS cursor, show or hide the on-screen keyboard, open a URL, play a sound, and set the default culture. - markup
- Register Rust-backed XAML
MarkupExtensions: Rust callbacks XAML can invoke as{myns:Foo positional_arg}. - mesh
- Code-built
MeshData+Meshelement for immediate-mode drawing. - multi_
binding MultiBinding+IMultiValueConverterfrom Rust.- name_
scope - Standalone
NameScope: the freestanding XAML namescope object, distinct from the per-FrameworkElementRegisterName/UnregisterNamepath (which routes through whatever scope already hosts the element). - plain_
vm - Plain (non-
DependencyObject) view models for data binding. - prelude
- Curated re-exports of the items most code reaches for. Glob-import it
(
use noesis_runtime::prelude::*;) to pull in the core view/element handles, the brush/transform/geometry traits and their common concrete types, data-binding and collection types, the custom-control and markup-extension surface, the provider traits, the lifecycle free functions, and the most-used enums. - reflection
- Runtime registration of “other reflected entities”: custom enums, custom
routed events on Rust-backed types, factory/metadata introspection, and the
reflection
TypeConverterstring→value path. - render_
device - Implement a custom GPU backend for Noesis by writing a Rust
Noesis::RenderDevice. - resources
ResourceDictionaryaccess + application resources.- shapes
- Build
Rectangle,Ellipse, andLineshapes from Rust and set their drawing properties without authoring XAML. - styles
Stylefrom code + template assignment.- svg
- SVG parsing and geometry queries, all CPU-side and headless. No GPU
RenderDeviceor render pass is needed, so you can use these in tests, tooling, or hit-testing without standing up a renderer. - text_
inlines - Code-built
TextBlockinline content: construct theInlineelement family (Run,Span,Bold,Italic,Underline,Hyperlink,LineBreak,InlineUIContainer) from Rust and assemble them into aTextBlock’s (or aSpan’s)InlineCollection. - texture_
provider - Supply image pixels to Noesis from Rust. Implement
TextureProviderto resolveImage.Source/ImageBrush.ImageSourceURIs into RGBA8 textures, then register it withset_texture_provider(or one of the scheme/assembly-scoped variants). Your boxed impl is handed to a C++RustTextureProvidersubclass through a vtable of trampolines, and the returnedRegisteredguard owns both the boxed impl and the C++ handle. - transforms
- Build
Transformobjects from Rust and apply them as an element’sRenderTransform. - typography
- Typography & text properties: the
FontFamilywrapper, theTextElementattached font properties (size / family / foreground / weight / style / stretch), a representative subset of the OpenTypeTypographyattached properties, and the IMECompositionUnderlinelist on aTextBox. - view
- Safe wrappers around the Noesis
FrameworkElement,IView, andIRendereropaque pointers. - xaml
- XAML loading variants.
- xaml_
provider - Teach Noesis where to find your XAML. Implement the
XamlProvidertrait, then callset_xaml_provider(or one of the scheme/assembly-scoped variants) to install it. Your boxed impl is handed to a C++RustXamlProvidersubclass through a vtable of trampolines, and the returnedRegisteredguard owns both the boxed impl and the C++ provider handle.
Functions§
- disable_
hot_ reload - Disable the Hot Reload feature before
init. Hot Reload is on by default in Debug/Profile SDK builds and costs a little extra memory; disabling it is purely an optimization. No-op onceinithas run, and a no-op on a Release dylib where the feature is compiled out. - disable_
inspector - Disable all remote Inspector connections before
init. The Inspector is enabled by default in Debug/Profile SDK builds (it opens a socket and waits for the remote tool); call this to keep it off. No-op afterinit/ on a Release dylib where the Inspector is compiled out. - disable_
socket_ init - Skip the Inspector’s socket initialization (e.g.
WSAStartupon Windows) beforeinit. Use this only when the host process has already initialized sockets itself, to avoid a double init. No-op afterinit/ on a Release dylib. - init
- Initialize Noesis subsystems. Call exactly once per process; Noesis does
not support re-init after
shutdown. - is_
inspector_ connected - Returns whether a remote Inspector is currently connected.
- set_
license - Optional. Apply Indie license credentials before
initto suppress the trial watermark. Pass empty strings (or skip the call) to run in trial mode. - shutdown
- Shut Noesis down. Call once at process exit, after all Noesis-owned objects have been released.
- update_
inspector - Keep the Inspector connection alive.
crate::view::Viewupdates call this internally, so it is only needed when the Inspector connects before any view exists. No-op on a Release dylib. - version
- Returns the Noesis runtime build version (e.g.
"3.2.13").