Skip to main content

Crate lumen_widget_macros

Crate lumen_widget_macros 

Source
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 the Widget impl in that case.
  • #[widget(prop)] on a field - parse from the attribute bag in Widget::spawn, read off the attribute of the field’s name (an element written <hello greeting="hi"/> sets greeting). Field type must implement std::str::FromStr or be a String (special-cased: copied verbatim).
  • #[widget(state)] on a field - leave at the struct’s Default value; never read from the attribute bag. Marker.

§What’s not covered in v1

  • Per-widget system registration. Authors still call app.add_systems(...) next to app.add_plugin(WidgetPlugin).
  • Nothing here: the generated plugin calls <Type>::register() in its build, 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.