mod utils;
use utils::*;
use bevy::prelude::*;
use jonmo::prelude::*;
fn main() {
let mut app = App::new();
let world = app.world_mut();
let colors = MutableVec::builder()
.values([random_color(), random_color()])
.spawn(world);
app.add_plugins(examples_plugin)
.insert_resource(Colors(colors.clone()))
.add_systems(
Startup,
(
move |world: &mut World| {
ui_root(colors.signal_vec()).spawn(world);
},
camera,
),
)
.add_systems(
Update,
(
live.run_if(any_with_component::<Lifetime>),
),
)
.run();
}
#[derive(Resource, Clone)]
struct Colors(MutableVec<Color>);
#[derive(Component, Default, Clone)]
struct Lifetime(f32);
fn ui_root(colors: impl SignalVec<Item = Color>) -> jonmo::Builder {
jonmo::Builder::from(Node {
height: Val::Percent(100.0),
width: Val::Percent(100.0),
flex_direction: FlexDirection::Column,
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
row_gap: Val::Px(10.0),
..default()
})
.children_signal_vec(
colors.enumerate().map_in(|(index, color)| item(index.dedupe(), color)),
)
.child(
jonmo::Builder::from((
Node {
height: Val::Px(40.),
width: Val::Px(100.),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
..default()
},
BackgroundColor(bevy::color::palettes::basic::GREEN.into()),
))
.on_spawn(|world, entity| {
world.entity_mut(entity).observe(
move |_: On<Pointer<Click>>,
colors: Res<Colors>,
mut mutable_vec_datas: Query<&mut MutableVecData<_>>| {
let mut guard = colors.0.write(&mut mutable_vec_datas);
guard.insert(guard.len(), random_color());
},
);
})
.child(jonmo::Builder::from((
Node::default(),
Text::new("+"),
TextColor(Color::WHITE),
TextLayout::new_with_justify(Justify::Center),
))),
)
}
#[derive(Component, Clone)]
struct Index(usize);
fn item(index: impl Signal<Item = Option<usize>> + Clone, color: Color) -> jonmo::Builder {
let lifetime_holder = LazyEntity::new();
jonmo::Builder::from((
Node {
height: Val::Px(40.0),
width: Val::Px(350.0),
align_items: AlignItems::Center,
flex_direction: FlexDirection::Row,
column_gap: Val::Px(10.0),
..default()
},
Lifetime::default(),
))
.lazy_entity(lifetime_holder.clone())
.child({
jonmo::Builder::from((
Node {
height: Val::Percent(100.),
width: Val::Percent(90.),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
..default()
},
BackgroundColor(color),
))
.child(
jonmo::Builder::from((
Node::default(),
Text::new(""),
TextColor(Color::BLACK), TextLayout::new_with_justify(Justify::Center),
))
.child((TextColor(Color::BLACK), TextSpan::new("item ")))
.child(
jonmo::Builder::from(TextColor(Color::BLACK)).component_signal(
index
.clone()
.map_in(|index| index.as_ref().map(ToString::to_string).map(TextSpan)),
),
)
.child((TextColor(Color::BLACK), TextSpan::new(" | lifetime: ")))
.child(
jonmo::Builder::from(TextColor(Color::BLACK)).component_signal(
signal::from_component_changed(lifetime_holder)
.map_in(|Lifetime(lifetime)| lifetime.round())
.dedupe()
.map_in_ref(ToString::to_string)
.map_in(TextSpan)
.map_in(Some),
),
),
)
})
.child(
jonmo::Builder::from((
Node {
height: Val::Percent(100.),
width: Val::Percent(10.),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
..default()
},
BackgroundColor(bevy::color::palettes::basic::RED.into()),
))
.on_spawn(|world, entity| {
world.entity_mut(entity).observe(
move |_: On<Pointer<Click>>,
indices: Query<&Index>,
colors: Res<Colors>,
mut mutable_vec_datas: Query<&mut MutableVecData<_>>| {
if let Ok(&Index(index)) = indices.get(entity) {
colors.0.write(&mut mutable_vec_datas).remove(index);
}
},
);
})
.component_signal(index.map_in(|index| index.map(Index)))
.child(jonmo::Builder::from((
Node::default(),
Text::new("x"),
TextColor(Color::WHITE),
TextLayout::new_with_justify(Justify::Center),
))),
)
}
fn camera(mut commands: Commands) {
commands.spawn(Camera2d);
}
fn live(mut lifetimes: Query<&mut Lifetime>, time: Res<Time>) {
for mut lifetime in lifetimes.iter_mut() {
lifetime.0 += time.delta_secs();
}
}