Expand description
#[derive(Widget)] - generates a [lumen_widget::Widget] impl plus a
companion Plugin struct for the annotated component.
§What gets emitted
Given:
ⓘ
use bevy_ecs::prelude::*;
use lumen_widget_macros::Widget;
#[derive(Component, Widget, Default)]
#[widget(tag = "hello")]
pub struct Hello {
#[widget(prop)] pub greeting: String,
#[widget(state)] pub shown: bool,
}the macro emits roughly:
ⓘ
impl ::lumen_widget::Widget for Hello {
fn name() -> &'static str { "Hello" }
fn parser_tag() -> &'static str { "hello" }
fn spawn(
entity: ::bevy_ecs::prelude::Entity,
attrs: &::lumen_widget::Attributes,
world: &mut ::bevy_ecs::prelude::World,
) {
let mut value: Hello = ::core::default::Default::default();
if let Some(v) = attrs.get("greeting") { value.greeting = v.into(); }
world.entity_mut(entity).insert(value);
}
}
impl Hello {
pub fn register() { ::lumen_widget::register_widget::<Hello>(); }
}
/// Plugin registering `Hello` with the App.
#[derive(Default, Debug, Clone, Copy)]
pub struct HelloPlugin;
impl ::lumen_core::app::Plugin for HelloPlugin {
fn name(&self) -> &'static str { "HelloPlugin" }
fn build(self, _app: &mut ::lumen_core::app::App) {
Hello::register();
// Widget-specific systems remain hand-written: authors
// call `app.add_systems(TickStage::Systems, my_system)`
// alongside `app.add_plugin(HelloPlugin)`. Future
// iterations may walk `#[widget(systems = "...")]` here.
}
}The paths above are the ones an engine crate gets, which depends on
lumen_widget, lumen_core and bevy_ecs itself. A crate whose manifest
depends on the Rust SDK (lumenui, under any name) gets the same items
through the SDK instead, ::lumenui::lumen_widget::Widget and so on, so an
app needs no dependency of its own on any of the three.
§Attribute reference
#[widget(tag = "name")]on the struct (required) - the markup tag handled by this widget.#[widget(name = "Hello")]on the struct (optional) - overrides the display name returned by [lumen_widget::Widget::name].#[widget(plugin = "MyExistingPlugin")]on the struct (optional): skip emitting a fresh Plugin struct; the author is providing their own. The derive only emits theWidgetimpl in that case.#[widget(prop)]on a field - parse from the attribute bag inWidget::spawn, read off the attribute of the field’s name (an element written<hello greeting="hi"/>setsgreeting). Field type must implementstd::str::FromStror be aString(special-cased: copied verbatim).#[widget(state)]on a field - leave at the struct’sDefaultvalue; never read from the attribute bag. Marker.
§What’s not covered in v1
- Per-widget system registration. Authors still call
app.add_systems(...)next toapp.add_plugin(WidgetPlugin). - Nothing here: the generated plugin calls
<Type>::register()in itsbuild, which publishes the tag into the registry the lumenc parser consults after its built-in tag table, so adding the generated plugin is enough for<my-thing>markup to parse.
Derive Macros§
- Widget
- The derive entry point. See the crate-level docs for the full surface.