Compare commits

...

7 Commits

@ -1,26 +0,0 @@
# Exploration
## Inspectors
### Model Inspector
- [ ] Construct Scene from Nodes/Meshes (not auto-scene builder)
- [ ] Show debug info about selected model
- [ ] Wireframe view
- [ ] Automatic tighter bounding box for selection
### Audio Inspector
- [ ] UI for selecting sound
- [ ] Play/Pause/Volume
- [x] Load sounds
- [ ] Scrolling list of sounds
## WASM
- [ ] Build and run using model/text inspector
- https://github.com/bevyengine/bevy/blob/main/examples/README.md#wasm
## Text Inspector
- [ ] Performance improvements?

@ -5,15 +5,15 @@
// TODO: // TODO:
// * Tree Organization: GLTF contains Animations and Scenes // * Tree Organization: GLTF contains Animations and Scenes
// * Camera can only select one at a time. // * Camera can only select one at a time.
// * (easy) Load audios like current GLTFs // * (hard) Better Colorscheme
// * (easy) Loop audio enable/disable
// * (easy) Better Colorscheme
// * (easy) Interactive buttons (hover/click)
// * (medium) Visual errors for bad GLTFs // * (medium) Visual errors for bad GLTFs
// * (medium) Collapsable containers (Gltfs, Animations, Scenes, Audio Clips, Cameras) // * (medium) Collapsable containers (Gltfs, Animations, Scenes, Audio Clips, Cameras)
// * (medium) Show/hide entire UI
// * (medium) Spawn clicked scene // * (medium) Spawn clicked scene
// * (medium) Play clicked animation // * (medium) Play clicked animation
// * (idea) Use enum instead of markers for exclusive UI // * (idea) Use enum instead of markers for exclusive UI
// * (medium) Add fonts similar to Audios based on inspect-fonts
// * (hard) Add Dialogs (requires text box UI, saving, loading)
use bevy::{ use bevy::{
asset::{AssetPath, Assets}, asset::{AssetPath, Assets},
@ -57,6 +57,7 @@ fn main() {
// Audio Systems // Audio Systems
load_audio, load_audio,
unload_audio, unload_audio,
manage_audio_ui,
play_audio, play_audio,
// Level Import/Export systems // Level Import/Export systems
export_level, export_level,
@ -72,7 +73,8 @@ fn main() {
#[derive(Debug, Component)] #[derive(Debug, Component)]
enum UiRef<T> { enum UiRef<T> {
Handle(T), Handle(T),
Entity(T), // Entity(T),
// Event(T),
} }
/// UI: /// UI:
@ -101,7 +103,13 @@ fn initialize_ui(mut commands: Commands) {
.spawn(( .spawn((
GameUiList, GameUiList,
Name::new("GLTFs"), Name::new("GLTFs"),
NodeBundle { ..default() }, NodeBundle {
style: Style {
flex_direction: FlexDirection::Column,
..default()
},
..default()
},
GltfsUi, GltfsUi,
)) ))
.with_children(|parent| { .with_children(|parent| {
@ -127,7 +135,13 @@ fn initialize_ui(mut commands: Commands) {
parent.spawn(( parent.spawn((
GameUiSet, GameUiSet,
Name::new("Audio Clips"), Name::new("Audio Clips"),
NodeBundle { ..default() }, NodeBundle {
style: Style {
flex_direction: FlexDirection::Column,
..default()
},
..default()
},
AudioClipsUi, AudioClipsUi,
)); ));
}); });
@ -135,7 +149,7 @@ fn initialize_ui(mut commands: Commands) {
fn load_bogus( fn load_bogus(
mut events: EventReader<KeyboardInput>, mut events: EventReader<KeyboardInput>,
root: Query<Entity, With<AnimationsUi>>, root: Query<Entity, (With<AnimationsUi>, Without<UiRef<Handle<AnimationClip>>>)>,
mut commands: Commands, mut commands: Commands,
) { ) {
events events
@ -197,7 +211,7 @@ fn get_fname(asset_path: AssetPath, suffixes: &[&str]) -> String {
/// This should be a separate async system /// This should be a separate async system
fn manage_gltf_ui( fn manage_gltf_ui(
mut events: EventReader<AssetEvent<Gltf>>, mut events: EventReader<AssetEvent<Gltf>>,
root: Query<Entity, With<GltfsUi>>, root: Query<Entity, (With<GltfsUi>, Without<UiRef<Handle<Gltf>>>)>,
mut commands: Commands, mut commands: Commands,
server: Res<AssetServer>, server: Res<AssetServer>,
) { ) {
@ -214,6 +228,9 @@ fn manage_gltf_ui(
_ => None, _ => None,
}) })
.for_each(|(handle, name)| { .for_each(|(handle, name)| {
root.iter().for_each(|entity| {
commands.entity(entity).log_components();
});
commands commands
.spawn(( .spawn((
GameUiButton, GameUiButton,
@ -236,7 +253,7 @@ struct ScenesUi;
/// Sync scene assets with UI /// Sync scene assets with UI
fn manage_scene_ui( fn manage_scene_ui(
mut events: EventReader<AssetEvent<Scene>>, mut events: EventReader<AssetEvent<Scene>>,
root: Query<Entity, With<ScenesUi>>, root: Query<Entity, (With<ScenesUi>, Without<UiRef<Handle<Scene>>>)>,
mut commands: Commands, mut commands: Commands,
gltfs: Res<Assets<Gltf>>, gltfs: Res<Assets<Gltf>>,
registry: Res<AssetRegistry>, registry: Res<AssetRegistry>,
@ -252,10 +269,6 @@ fn manage_scene_ui(
|gltf_handle| match gltfs.get(&gltf_handle.clone().typed::<Gltf>()) { |gltf_handle| match gltfs.get(&gltf_handle.clone().typed::<Gltf>()) {
Some(gltf) => { Some(gltf) => {
gltf.named_scenes.iter().find_map(|(name, scene_handle)| { gltf.named_scenes.iter().find_map(|(name, scene_handle)| {
info!(
"scene_handle({:?}) == handle({:?})",
scene_handle, handle
);
(scene_handle == handle).then_some(name) (scene_handle == handle).then_some(name)
}) })
} }
@ -292,7 +305,7 @@ struct AnimationsUi;
fn manage_animation_ui( fn manage_animation_ui(
mut events: EventReader<AssetEvent<AnimationClip>>, mut events: EventReader<AssetEvent<AnimationClip>>,
root: Query<Entity, With<AnimationsUi>>, root: Query<Entity, (With<AnimationsUi>, Without<UiRef<Handle<AnimationClip>>>)>,
mut commands: Commands, mut commands: Commands,
gltfs: Res<Assets<Gltf>>, gltfs: Res<Assets<Gltf>>,
registry: Res<AssetRegistry>, registry: Res<AssetRegistry>,
@ -309,10 +322,6 @@ fn manage_animation_ui(
match gltfs.get(&gltf_handle.clone().typed::<Gltf>()) { match gltfs.get(&gltf_handle.clone().typed::<Gltf>()) {
Some(gltf) => gltf.named_animations.iter().find_map( Some(gltf) => gltf.named_animations.iter().find_map(
|(name, animation_handle)| { |(name, animation_handle)| {
info!(
"animation_handle({:?}) == handle({:?})",
animation_handle, handle
);
(animation_handle == handle).then_some(name) (animation_handle == handle).then_some(name)
}, },
), ),
@ -342,7 +351,83 @@ fn manage_animation_ui(
struct AudioClipsUi; struct AudioClipsUi;
/// Drag+Drop import Audio to editor /// Drag+Drop import Audio to editor
fn load_audio() {} fn load_audio(
mut events: EventReader<FileDragAndDrop>,
server: Res<AssetServer>,
mut assets: ResMut<AssetRegistry>,
) {
events
.iter()
.filter_map(|event| match event {
FileDragAndDrop::DroppedFile { path_buf, .. } => Some(path_buf),
_ => None,
})
.for_each(|path_buf| {
let path = path_buf.as_path();
let handle = server.load_untyped(path);
assets.0.insert(handle);
});
}
fn manage_audio_ui(
mut events: EventReader<AssetEvent<AudioSource>>,
root: Query<Entity, (With<AudioClipsUi>, Without<AudioSink>)>,
mut commands: Commands,
server: Res<AssetServer>,
) {
events
.iter()
.filter_map(|event| match event {
AssetEvent::Created { handle } => {
let asset_path = server
.get_handle_path(handle.clone())
.expect("Fetch Asset Path");
let name = get_fname(asset_path, &[".ogg"]);
Some((handle.clone(), String::from(name)))
}
_ => None,
})
.for_each(|(handle, name)| {
commands
.spawn((
GameUiButton,
Name::new(name),
NodeBundle { ..default() },
AudioClipsUi,
AudioBundle {
source: handle.clone(),
settings: PlaybackSettings {
mode: bevy::audio::PlaybackMode::Loop,
paused: true,
..default()
},
},
))
.set_parent(root.single());
});
}
/// Play/Loop Audio
fn play_audio(
mut events: Query<
(&Interaction, &AudioSink, &mut UiElementState),
(Changed<Interaction>, With<AudioClipsUi>),
>,
) {
events
.iter_mut()
.for_each(|(interaction, sink, mut state)| match interaction {
Interaction::Pressed => {
sink.toggle();
*state = match *state {
UiElementState::Enabled => UiElementState::Active,
_ => UiElementState::Enabled,
}
}
_ => (),
});
}
/// Remove audio from editor /// Remove audio from editor
fn unload_audio() {} fn unload_audio() {}
@ -350,9 +435,6 @@ fn unload_audio() {}
/// Spawn Scene /// Spawn Scene
fn spawn_scene() {} fn spawn_scene() {}
/// Play/Loop Audio
fn play_audio() {}
/// Export level /// Export level
fn export_level() {} fn export_level() {}

@ -1,101 +1,350 @@
use bevy::{input::mouse::MouseWheel, prelude::*}; use bevy::{
input::{keyboard::KeyboardInput, ButtonState},
prelude::*,
window::PrimaryWindow,
};
use monologue_trees::{debug::*, ui::*};
fn main() { fn main() {
App::new() App::new()
.add_plugins(DefaultPlugins.set(WindowPlugin { .add_plugins((
DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window { primary_window: Some(Window {
title: "UI WTF".into(), title: "UI WTF".into(),
resolution: (640., 480.).into(), resolution: (640., 480.).into(),
..default() ..default()
}), }),
..default() ..default()
})) }),
.add_systems(Startup, (init,)) GameUiPlugin,
.add_systems(Update, (scroll,)) ))
// .init_resource::<Icon>()
.add_systems(Startup, init_ui2)
.add_systems(Update, toggle)
// .add_systems(Startup, init_ui)
// .add_systems(Update, (cursors, container()))
.run(); .run();
} }
#[derive(Component)] fn container() -> NodeBundle {
struct ScrollingList;
fn init(mut commands: Commands) {
info!("Spawning camera");
commands.spawn(Camera2dBundle { ..default() });
info!("Initializing UI");
commands
.spawn(NodeBundle {
background_color: BackgroundColor(Color::WHITE),
style: Style {
justify_content: JustifyContent::Center,
width: Val::Percent(90.0),
height: Val::Percent(90.0),
overflow: Overflow::clip(),
..default()
},
..default()
})
.with_children(|parent| {
parent
.spawn((
NodeBundle { NodeBundle {
background_color: BackgroundColor(Color::OLIVE),
style: Style { style: Style {
flex_wrap: FlexWrap::Wrap, border: UiRect::all(Val::Px(2.0)),
flex_direction: FlexDirection::Row, right: Val::Percent(-100.0),
justify_content: JustifyContent::SpaceAround, top: Val::Px(-4.0),
width: Val::Auto, flex_direction: FlexDirection::Column,
height: Val::Auto, display: Display::None,
max_width: Val::Auto,
max_height: Val::Auto,
..default() ..default()
}, },
background_color: BackgroundColor(Color::PURPLE),
border_color: BorderColor(Color::BLACK),
..default() ..default()
}, }
ScrollingList, }
))
.with_children(|parent| { fn spec(color: Color) -> ButtonBundle {
info!("Initializing Child Element"); ButtonBundle {
let colors = [
Color::ORANGE,
Color::BLUE,
Color::GREEN,
Color::SALMON,
Color::SEA_GREEN,
Color::MAROON,
Color::ORANGE,
Color::BLUE,
Color::GREEN,
Color::SALMON,
Color::SEA_GREEN,
Color::MAROON,
];
for i in 0..12 {
parent.spawn(NodeBundle {
background_color: BackgroundColor(colors[i]),
style: Style { style: Style {
width: Val::Px(256.0), border: UiRect::all(Val::Px(2.0)),
height: Val::Px(256.0), width: Val::Px(100.0),
padding: UiRect::all(Val::Px(5.0)), height: Val::Px(50.0),
flex_direction: FlexDirection::Column,
..default() ..default()
}, },
background_color: BackgroundColor(color),
border_color: BorderColor(Color::BLACK),
..default() ..default()
});
} }
});
});
} }
fn scroll( fn toggle(
mut scroll_evr: EventReader<MouseWheel>, mut events: Query<
mut query: Query<&mut Style, With<ScrollingList>>, (&mut BackgroundColor, &Interaction, &Children),
(Changed<Interaction>, With<Button>),
>,
mut styles: Query<&mut Style>,
) { ) {
for ev in scroll_evr.iter() { events
for mut s in query.iter_mut() { .iter_mut()
s.top = match s.top { .for_each(|(mut bg_color, interaction, children)| match interaction {
Val::Px(current) => Val::Px(current + (ev.y * 5.0)), Interaction::Pressed => {
_ => Val::Px(0.0), bg_color.0 = Color::RED;
children.iter().for_each(|&child| {
if let Ok(mut style) = styles.get_mut(child) {
style.display = match style.display {
Display::Flex => Display::None,
Display::None | _ => Display::Flex,
}; };
} }
});
}
Interaction::Hovered => {
bg_color.0 = Color::RED;
}
Interaction::None => {
bg_color.0 = Color::PINK;
} }
});
} }
// const CURSORS: [CursorIcon; 35] = [
// CursorIcon::Default,
// CursorIcon::Crosshair,
// CursorIcon::Hand,
// CursorIcon::Arrow,
// CursorIcon::Move,
// CursorIcon::Text,
// CursorIcon::Wait,
// CursorIcon::Help,
// CursorIcon::Progress,
// CursorIcon::NotAllowed,
// CursorIcon::ContextMenu,
// CursorIcon::Cell,
// CursorIcon::VerticalText,
// CursorIcon::Alias,
// CursorIcon::Copy,
// CursorIcon::NoDrop,
// CursorIcon::Grab,
// CursorIcon::Grabbing,
// CursorIcon::AllScroll,
// CursorIcon::ZoomIn,
// CursorIcon::ZoomOut,
// CursorIcon::EResize,
// CursorIcon::NResize,
// CursorIcon::NeResize,
// CursorIcon::NwResize,
// CursorIcon::SResize,
// CursorIcon::SeResize,
// CursorIcon::SwResize,
// CursorIcon::WResize,
// CursorIcon::EwResize,
// CursorIcon::NsResize,
// CursorIcon::NeswResize,
// CursorIcon::NwseResize,
// CursorIcon::ColResize,
// CursorIcon::RowResize,
// ];
fn init_ui2(mut commands: Commands) {
commands.spawn((
Camera2dBundle { ..default() },
UiCameraConfig { show_ui: true },
));
commands
.spawn(NodeBundle {
style: Style {
border: UiRect::all(Val::Px(2.0)),
flex_direction: FlexDirection::Column,
..default()
},
background_color: BackgroundColor(Color::PURPLE),
border_color: BorderColor(Color::BLACK),
..default()
})
.with_children(|parent| {
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
});
});
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
});
});
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
});
});
});
});
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
});
});
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
});
});
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
});
});
});
});
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
});
});
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
});
});
parent.spawn(spec(Color::PINK)).with_children(|parent| {
parent.spawn(container()).with_children(|parent| {
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
parent.spawn(spec(Color::PINK));
});
});
});
});
});
}
// #[derive(Debug, Component, Resource, Default)]
// struct Icon(CursorIcon);
//
// fn init_ui(mut commands: Commands) {
// commands.spawn((
// Camera2dBundle { ..default() },
// UiCameraConfig { show_ui: true },
// ));
//
// commands
// .spawn(NodeBundle {
// style: Style {
// height: Val::Percent(100.0),
// width: Val::Percent(100.0),
// justify_content: JustifyContent::Start,
// align_items: AlignItems::Start,
// ..default()
// },
// background_color: BackgroundColor(Color::GRAY),
// ..default()
// })
// .with_children(|parent| {
// parent
// .spawn((
// GameUiNav,
// // Name::new("Game Nav"),
// NodeBundle { ..default() },
// ))
// .with_children(|parent| {
// parent
// .spawn((
// GameUiTab,
// Name::new("Grow/Shrink Tab"),
// NodeBundle { ..default() },
// ))
// .with_children(|parent| {
// parent.spawn((
// container,
// GameUiSet,
// // Name::new("Grow/Shrink Set"),
// NodeBundle { ..default() },
// ));
// });
//
// parent
// .spawn((
// GameUiTab,
// Name::new("Cursor Icons Tab"),
// NodeBundle { ..default() },
// ))
// .with_children(|parent| {
// parent
// .spawn((
// GameUiSet,
// // Name::new("Cursor Icons Set"),
// NodeBundle { ..default() },
// ))
// .with_children(|parent| {
// CURSORS.iter().for_each(|&icon| {
// parent.spawn((
// GameUiButton,
// Name::new(format!("{:?}", icon)),
// NodeBundle { ..default() },
// Icon(icon),
// ));
// });
// });
// });
// });
// });
// }
//
// fn cursors(
// events: Query<(&Interaction, &Icon), (Changed<Interaction>, With<Button>)>,
// mut primary_window: Query<&mut Window, With<PrimaryWindow>>,
// mut curr: ResMut<Icon>,
// ) {
// events.iter().for_each(|(&interaction, &ref icon)| {
// let mut window = primary_window.single_mut();
//
// match interaction {
// Interaction::Hovered => {
// (*window).cursor.icon = icon.0.clone();
// }
// Interaction::Pressed => {
// curr.0 = icon.0.clone();
// }
// Interaction::None => {
// (*window).cursor.icon = curr.0.clone();
// }
// }
// })
// }
//
// #[derive(Debug, Component)]
// struct container;
//
// fn container(
// mut events: EventReader<KeyboardInput>,
// mut commands: Commands,
// root: Query<Entity, With<container>>,
// children: Query<&Children, With<container>>,
// ) {
// events.iter().for_each(
// |KeyboardInput {
// key_code, state, ..
// }| {
// match (key_code, state) {
// (Some(KeyCode::Up), ButtonState::Pressed) => {
// commands.entity(root.single()).with_children(|parent| {
// parent.spawn((
// GameUiButton,
// Name::new("asdfwtf"),
// NodeBundle { ..default() },
// ));
// });
// }
// (Some(KeyCode::Down), ButtonState::Pressed) => {
// children.single().iter().last().iter().for_each(|&&child| {
// commands.entity(child).despawn_recursive();
// });
// }
// _ => (),
// }
// },
// )
// }

@ -1,121 +1,101 @@
/// TODO:
/// * Titles on top left of window/tab
/// *
use bevy::{prelude::*, window::PrimaryWindow}; use bevy::{prelude::*, window::PrimaryWindow};
pub struct GameUiPlugin; pub struct GameUiPlugin;
impl Plugin for GameUiPlugin { impl Plugin for GameUiPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems( app.add_systems(PreUpdate, (spawn_nav, spawn_tab, spawn_set, spawn_button))
Update, .add_systems(Update, (manage_names, manage_tab));
(
manage_ui_list,
manage_ui_set,
manage_ui_button,
manage_cursor,
),
);
} }
} }
/// GameUiList for holding ordered collections of objects /// Navigation UI Container
#[derive(Debug, Component)] /// Buttons in a nav correspond to Tabs in a navbar/navmenu
pub struct GameUiList; #[derive(Component, PartialEq)]
pub struct GameUiNav;
/// Manage UI Lists: lists of UI entities. /// Sets contain a variety of elements like action buttons
fn manage_ui_list(events: Query<(Entity, &Name), Added<GameUiList>>, mut commands: Commands) { /// Usually the "leaf" of a navigation tree
events.iter().for_each(|(entity, name)| { #[derive(Component, PartialEq)]
commands pub struct GameUiSet;
.entity(entity)
.insert(NodeBundle { /// Buttons are used for interaction in the UI
style: Style { #[derive(Component, PartialEq)]
// width: Val::Px(100.0), pub struct GameUiButton;
margin: UiRect::all(Val::Px(2.0)),
padding: UiRect::all(Val::Px(2.0)), #[derive(Component, PartialEq)]
border: UiRect::all(Val::Px(2.0)), pub struct GameUiTab;
flex_direction: FlexDirection::Column,
align_items: AlignItems::Stretch, fn spawn_nav(events: Query<(Entity, &GameUiNav), Added<GameUiNav>>, mut commands: Commands) {
justify_items: JustifyItems::Center, events.iter().for_each(|(entity, _)| {
align_content: AlignContent::FlexStart, info!("Spawning Nav UI");
..default()
},
background_color: BackgroundColor(Color::RED),
border_color: BorderColor(Color::BLACK),
..default()
})
.with_children(|parent| {
parent.spawn(TextBundle::from_section(name, TextStyle { ..default() }));
});
}); });
} }
/// GameUiSet Component for holding collections of objects fn spawn_tab(events: Query<Entity, Added<GameUiTab>>, mut commands: Commands) {
#[derive(Debug, Component)] events.iter().for_each(|entity| {});
pub struct GameUiSet; }
/// Manage UI Sets: collections of UI entities. fn spawn_set(events: Query<Entity, Added<GameUiSet>>, mut commands: Commands) {
fn manage_ui_set(events: Query<(Entity, &Name), Added<GameUiSet>>, mut commands: Commands) { events.iter().for_each(|entity| {});
events.iter().for_each(|(entity, name)| { }
commands
.entity(entity) fn spawn_button(
.insert(NodeBundle { events: Query<(Entity, &GameUiButton), Added<GameUiButton>>,
mut commands: Commands,
) {
events.iter().for_each(|(entity, _)| {
info!("Spawning UI Button");
commands.entity(entity).insert(ButtonBundle {
style: Style { style: Style {
// width: Val::Px(100.0), padding: UiRect::all(Val::Px(3.0)),
margin: UiRect::all(Val::Px(2.0)), margin: UiRect::all(Val::Px(3.0)),
padding: UiRect::all(Val::Px(2.0)),
border: UiRect::all(Val::Px(2.0)),
align_items: AlignItems::FlexStart,
align_content: AlignContent::FlexStart,
flex_direction: FlexDirection::Row,
flex_wrap: FlexWrap::Wrap,
..default() ..default()
}, },
background_color: BackgroundColor(Color::BLUE), background_color: BackgroundColor(Color::BLUE),
border_color: BorderColor(Color::BLACK),
..default() ..default()
})
.with_children(|parent| {
parent.spawn(TextBundle::from_section(name, TextStyle { ..default() }));
}); });
}); });
} }
/// GameUiButton for interactive elements fn manage_names(
#[derive(Debug, Component)] events: Query<
pub struct GameUiButton; (Entity, &Name),
(
/// Manage UI Buttons. interactive buttons. Or<(With<GameUiNav>, With<GameUiButton>)>,
fn manage_ui_button(events: Query<(Entity, &Name), Added<GameUiButton>>, mut commands: Commands) { Or<(Added<Name>, Changed<Name>)>,
),
>,
mut commands: Commands,
) {
events.iter().for_each(|(entity, name)| { events.iter().for_each(|(entity, name)| {
commands commands.entity(entity).with_children(|parent| {
.entity(entity) parent
.insert(ButtonBundle { .spawn(NodeBundle {
style: Style { style: Style {
margin: UiRect::all(Val::Px(2.0)), align_self: AlignSelf::FlexStart,
padding: UiRect::all(Val::Px(2.0)), padding: UiRect::all(Val::Px(3.0)),
border: UiRect::all(Val::Px(2.0)), margin: UiRect::all(Val::Px(3.0)),
justify_content: JustifyContent::Center,
..default() ..default()
}, },
background_color: BackgroundColor(Color::GREEN), background_color: BackgroundColor(Color::CRIMSON),
border_color: BorderColor(Color::BLACK),
..default() ..default()
}) })
.with_children(|parent| { .with_children(|parent| {
parent.spawn(TextBundle::from_section(name, TextStyle::default())); parent.spawn(TextBundle::from_section(
name.as_str(),
TextStyle { ..default() },
));
});
}); });
}); });
} }
/// Manage the cursor icon for better immersion fn manage_tab(events: Query<&Interaction, Changed<Interaction>>) {
fn manage_cursor( events.iter().for_each(|interaction| {
mut primary_window: Query<&mut Window, With<PrimaryWindow>>, info!("When tab is clicked, show/hide content");
events: Query<&Interaction, With<Interaction>>,
) {
events.iter().for_each(|event| {
let mut window = primary_window.single_mut();
window.cursor.icon = match event {
Interaction::Pressed => CursorIcon::Grabbing,
Interaction::Hovered => CursorIcon::Hand,
Interaction::None => CursorIcon::Default,
}
}); });
} }

14
tmp

@ -1,14 +0,0 @@
if *duration > Duration::ZERO {
let mut text = texts.single_mut();
let total_sections = text.sections.len();
*duration = duration.saturating_sub(time.delta());
for (idx, section) in text.sections.iter_mut().enumerate() {
let ratio = ((idx + 1) as f32) / (total_sections as f32);
let cursor = 1.0 - ((*duration).as_secs_f32() / 30.0);
let alpha = if cursor > ratio { 1.0 } else { 0.0 };
section.style.color.set_a(alpha);
}
}
Loading…
Cancel
Save