Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to pass a font asset handle to a style builder? #29

Open
musjj opened this issue Sep 9, 2024 · 4 comments
Open

How to pass a font asset handle to a style builder? #29

musjj opened this issue Sep 9, 2024 · 4 comments

Comments

@musjj
Copy link

musjj commented Sep 9, 2024

I'm trying to pass a handle:

#[derive(Clone, PartialEq)]
pub struct MyUi;

impl ViewTemplate for MyUi {
    type View = impl View;

    fn create(&self, cx: &mut Cx) -> Self::View {
        let font_assets = cx.use_resource::<MyFontAssets>();
        let font = font_assets.comic_sans.clone();

        Element::<NodeBundle>::new().style(move |ss: &mut StyleBuilder| {
            ss.font(font);
        })
    }
}

But it doesn't work because the style builder function must be Fn:

expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
required for `{closure@src/my_ui.rs:26:44: 26:72}` to implement `bevy_mod_stylebuilder::StyleTuple`

Is there a way to make font handles work with quill?

@viridia
Copy link
Owner

viridia commented Sep 9, 2024

Hmmm, not sure why this doesn't work. That being said, there's a few things you can do right now:

  1. Use style_dyn, and pass in the font handle as an explicit dependency.

  2. Instead of passing in a handle, ss.font() should be able to accept the asset path string directly, e.g. .font("embedded://bevy_quill_obsidian/assets/fonts/Open_Sans/static/OpenSans-Medium.ttf").

@musjj
Copy link
Author

musjj commented Sep 10, 2024

Thanks, but I ended up inserting InheritableFontStyles at the root node instead:

Element::<NodeBundle>::new()
    .insert(InheritableFontStyles {
        ...
    })

Use style_dyn, and pass in the font handle as an explicit dependency.

I'll try this if I ever need to override the font on a specific node.

Instead of passing in a handle, ss.font() should be able to accept the asset path string directly, e.g. .font("embedded://bevy_quill_obsidian/assets/fonts/Open_Sans/static/OpenSans-Medium.ttf").

This won't work well for me, because I want to have the font fully loaded before the game starts (I'm using bevy_asset_loader)

EDIT: It looks like even when passing it as dep with style_dyn you still need to call .clone() on the resource or you'll get a lifetime error.

To clarify, this is what my resource looks like:

#[derive(AssetCollection, Clone, Resource, PartialEq, PartialOrd, Eq)]
pub struct MyAssets {
    #[asset(path = "foobar.png")]
    pub foobar: Handle<Image>,
    // ...and tens of other asset fields
}

I wonder if there's a more efficient approach that avoids cloning.

@musjj
Copy link
Author

musjj commented Sep 10, 2024

Ok, I figured it out:

#[derive(Clone, PartialEq)]
pub struct MyUi;

impl ViewTemplate for MyUi {
    type View = impl View;

    fn create(&self, cx: &mut Cx) -> Self::View {
        let font_assets = cx.use_resource::<MyFontAssets>();
        let font = font_assets.comic_sans.clone();

        Element::<NodeBundle>::new().style(move |ss: &mut StyleBuilder| {
            ss.font(font.clone()); // <- you need to clone it so that the closure becomes `Fn`
                                   // See: https://doc.rust-lang.org/std/keyword.move.html
        })
    }
}

It seems that this is more of a Rust issue, so I think I'll close this. But before that, would it be possible for .style() and other callbacks to be a FnOnce instead? Do they need to be called multiple times?

@viridia
Copy link
Owner

viridia commented Sep 10, 2024

FnOnce: Certainly worth investigating.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants