-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Bevy Feathers: an opinionated widget toolkit for building Bevy tooling #19730
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
Conversation
The generated |
/// A component that specifies the cursor icon to be used when the mouse is not hovering over | ||
/// any other entity. This is used to set the default cursor icon for the window. | ||
#[derive(Resource, Debug, Clone, Default)] | ||
pub struct DefaultCursorIcon(pub CursorIcon); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Follow-up: we should probably move this out into bevy_window or something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a number of things in here that I expect will eventually "graduate". This includes the theming framework.
/// Rounded corners options | ||
pub corners: RoundedCorners, | ||
/// Click handler | ||
pub on_click: Option<SystemId>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the use case of a button without any click handler? It seems to me like using an Option here is adding boilerplate to the most common case. It doesn't really matter to be clear, I'm just curious of the reason why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the main reason is that during prototyping you may want to create your layout and don't have your handlers defined yet. I admit that this is a somewhat trivial use case.
Eventually I suspect that Option<SystemId>
will get replaced with an enum allowing a system id, a cached system, "Ignore", or other options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the SystemId
based design is the thing I'm most nervous about in this whole design. I'd like to revisit it, but not in this PR.
#[derive(Clone, Debug)] | ||
pub enum HandleOrPath<T: Asset> { | ||
/// Specify the asset reference as a handle. | ||
Handle(Handle<T>), | ||
/// Specify the asset reference as a [`String`]. | ||
Path(String), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i wonder if this should be in bevy_asset
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do something similar with Shaders. It would be nice for this pattern to be more generalized, but it's a bit out of scope here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i had a suspicion that there was somewhere that already had this, i had in my head that it was in bevy_gltf
but the type that appears there has more information
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, spin this out in follow-up.
crates/bevy_feathers/src/palette.rs
Outdated
//! The Feathers standard color palette. | ||
use bevy_color::Color; | ||
|
||
/// Black | ||
pub const BLACK: Color = Color::oklcha(0.0, 0.0, 0.0, 1.0); | ||
/// Gray 0 - window background | ||
pub const GRAY_0: Color = Color::oklcha(0.2414, 0.0095, 285.67, 1.0); | ||
/// Gray 1 - pane background | ||
pub const GRAY_1: Color = Color::oklcha(0.2866, 0.0072, 285.93, 1.0); | ||
/// Gray 2 - item background | ||
pub const GRAY_2: Color = Color::oklcha(0.3373, 0.0071, 274.77, 1.0); | ||
/// Gray 3 - item background (active) | ||
pub const GRAY_3: Color = Color::oklcha(0.3992, 0.0101, 278.38, 1.0); | ||
/// Warm Gray 3 - border | ||
pub const WARM_GRAY_1: Color = Color::oklcha(0.3757, 0.0017, 286.32, 1.0); | ||
/// Light Gray 1 - bright label text | ||
pub const LIGHT_GRAY_1: Color = Color::oklcha(0.7607, 0.0014, 286.37, 1.0); | ||
/// Light Gray 2 - dim label text | ||
pub const LIGHT_GRAY_2: Color = Color::oklcha(0.6106, 0.003, 286.31, 1.0); | ||
/// White - button label text | ||
pub const WHITE: Color = Color::oklcha(1.0, 0.000000059604645, 90.0, 1.0); | ||
/// Accent - call-to-action and selection color | ||
pub const ACCENT: Color = Color::oklcha(0.542, 0.1594, 255.4, 1.0); | ||
/// Dark Coral - for X-axis inputs and drag handles | ||
pub const X_AXIS: Color = Color::oklcha(0.5232, 0.1404, 13.84, 1.0); | ||
/// Olive - for Y-axis inputs and drag handles | ||
pub const Y_AXIS: Color = Color::oklcha(0.5866, 0.1543, 129.84, 1.0); | ||
/// Steel Blue - for Z-axis inputs and drag handles | ||
pub const Z_AXIS: Color = Color::oklcha(0.4847, 0.1249, 253.08, 1.0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These colors are, most of them, related to the colors used by the dark theme, right? other themes would not use most of these, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That decision is above my pay grade...or maybe below it. I don't know the answer :)
Right now I am making as few assumptions as I can.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're going to focus on a dark theme only for now.
#[derive(Default, Clone)] | ||
pub struct ThemeProps { | ||
/// Map of design tokens to colors. | ||
pub color: HashMap<String, Color>, | ||
// Other style property types to be added later. | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this should be an asset, and have an asset loader, and have the dark theme already as an asset so that people creating custom themes already have an starting point
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's designed so that it could potentially be an asset - just slap some serde derives on there and you are good to go. But I don't want to do that now. And particularly, for small things like the world inspector, any kind of filesystem dependencies should be avoided. So being able to define themes in code is also a feature.
crates/bevy_feathers/src/theme.rs
Outdated
pub mod tokens { | ||
/// Window background | ||
pub const WINDOW_BG: &str = "window.bg"; | ||
|
||
/// Focus ring | ||
pub const FOCUS_RING: &str = "focus"; | ||
|
||
/// Regular text | ||
pub const TEXT_MAIN: &str = "text.main"; | ||
/// Dim text | ||
pub const TEXT_DIM: &str = "text.dim"; | ||
|
||
// Normal buttons | ||
|
||
/// Regular button background | ||
pub const BUTTON_BG: &str = "button.bg"; | ||
/// Regular button background (hovered) | ||
pub const BUTTON_BG_HOVER: &str = "button.bg.hover"; | ||
/// Regular button background (disabled) | ||
pub const BUTTON_BG_DISABLED: &str = "button.bg.disabled"; | ||
/// Regular button background (pressed) | ||
pub const BUTTON_BG_PRESSED: &str = "button.bg.pressed"; | ||
/// Regular button text | ||
pub const BUTTON_TEXT: &str = "button.txt"; | ||
/// Regular button text (disabled) | ||
pub const BUTTON_TEXT_DISABLED: &str = "button.txt.disabled"; | ||
|
||
// Primary ("default") buttons | ||
|
||
/// Primary button background | ||
pub const BUTTON_PRIMARY_BG: &str = "button.primary.bg"; | ||
/// Primary button background (hovered) | ||
pub const BUTTON_PRIMARY_BG_HOVER: &str = "button.primary.bg.hover"; | ||
/// Primary button background (disabled) | ||
pub const BUTTON_PRIMARY_BG_DISABLED: &str = "button.primary.bg.disabled"; | ||
/// Primary button background (pressed) | ||
pub const BUTTON_PRIMARY_BG_PRESSED: &str = "button.primary.bg.pressed"; | ||
/// Primary button text | ||
pub const BUTTON_PRIMARY_TEXT: &str = "button.primary.txt"; | ||
/// Primary button text (disabled) | ||
pub const BUTTON_PRIMARY_TEXT_DISABLED: &str = "button.primary.txt.disabled"; | ||
|
||
// Slider | ||
|
||
/// Background for slider | ||
pub const SLIDER_BG: &str = "slider.bg"; | ||
/// Background for slider moving bar | ||
pub const SLIDER_BAR: &str = "slider.bar"; | ||
/// Background for slider moving bar (disabled) | ||
pub const SLIDER_BAR_DISABLED: &str = "slider.bar.disabled"; | ||
/// Background for slider text | ||
pub const SLIDER_TEXT: &str = "slider.text"; | ||
/// Background for slider text (disabled) | ||
pub const SLIDER_TEXT_DISABLED: &str = "slider.text.disabled"; | ||
|
||
// Checkbox | ||
|
||
/// Checkbox border around the checkmark | ||
pub const CHECKBOX_BORDER: &str = "checkbox.border"; | ||
/// Checkbox border around the checkmark (hovered) | ||
pub const CHECKBOX_BORDER_HOVER: &str = "checkbox.border.hover"; | ||
/// Checkbox border around the checkmark (disabled) | ||
pub const CHECKBOX_BORDER_DISABLED: &str = "checkbox.border.disabled"; | ||
/// Checkbox check mark | ||
pub const CHECKBOX_MARK: &str = "checkbox.mark"; | ||
/// Checkbox check mark (disabled) | ||
pub const CHECKBOX_MARK_DISABLED: &str = "checkbox.mark.disabled"; | ||
/// Checkbox label text | ||
pub const CHECKBOX_TEXT: &str = "checkbox.text"; | ||
/// Checkbox label text (disabled) | ||
pub const CHECKBOX_TEXT_DISABLED: &str = "checkbox.text.disabled"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these generic enough that any app would use them or are these more related to the editor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I am going for here is any kind of app that is "editor-like" - that includes the Bevy editor, the world inspector, a substance builder, tree-growth editor and so on.
Eventually the parts that aren't editor specific can be extracted and put into their own crates. But I'd like things to mature before that.
children![ | ||
button( | ||
ButtonProps { | ||
on_click: Some(commands.register_system(|| { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't kept up with all the various ecs and bsn work. So out of curisoity, is there a future where we'll be able to do something like this:
ButtonProps {
on_click: || {
info!("clicked!");
},
..default()
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I would like to be able to do that. I need to take a proper crack at the code here though.
} | ||
|
||
/// An observer which looks for changes to the `InheritableFont` component on an entity, and | ||
/// propagates downward the text color to all participating text entities. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This propagates the font, not the text color?
ColorStop::new(Color::NONE, Val::Percent(0.)), | ||
ColorStop::new(Color::NONE, Val::Percent(50.)), | ||
ColorStop::new(Color::NONE, Val::Percent(50.)), | ||
ColorStop::new(Color::NONE, Val::Percent(100.)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The zero and one hundred percent stops can be elided here. If there is space before the first stop or after the last stop it fills with the respective stop's color.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that this is more explicit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess so, I mean I'm just fussing as usual. But it's also a little more complicated to update the colors as there are four values to change instead of two.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how I feel about the embedded fonts, but since it's behind a feature it doesn't matter that much.
Other than that LGTM
Simplified slider and button props, default now works. Removed rough draft comments. Finished slider styling observer I forgot to implement. Improved release notes.
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
* Break up theme module * Improved module docs * Rename "dark" to "dark_theme"
I'm happy with this as a base. There's lots to explore and follow-up on, but let's get this merged and let people start experimenting :) |
Objective
This PR introduces Bevy Feathers, an opinionated widget toolkit and theming system intended for use by the Bevy Editor, World Inspector, and other tools.
The
bevy_feathers
crate is incomplete and hidden behind an experimental feature flag. The API is going to change significantly before release.