Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions examples/widget_gallery.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Counter UI example.

use actuate::prelude::*;
use bevy::{asset::io::SeekForwardFuture, prelude::*};

// Counter composable.
#[derive(Data)]
struct WidgetGallery;

impl Compose for WidgetGallery {
fn compose(cx: Scope<Self>) -> impl Compose {
let is_shown = use_mut(&cx, || true);
// let selected_value = use_mut(&cx, || 5.);

material_ui((
radio_button().is_enabled(*is_shown),
switch()
.is_enabled(*is_shown)
.on_click(move || SignalMut::update(is_shown, |x| *x = !*x)),
// slider().current(*selected_value),
))
.width(Val::Vw(100.))
}
}

fn setup(mut commands: Commands) {
commands.spawn(Camera2d::default());

// Spawn a composition with a `Counter`, adding it to the Actuate runtime.
commands.spawn((
Node {
flex_direction: FlexDirection::Column,
align_items: AlignItems::Center,
row_gap: Val::Px(10.),
..default()
},
Composition::new(WidgetGallery),
));
}

fn main() {
App::new()
.add_plugins((DefaultPlugins, ActuatePlugin))
.add_systems(Startup, setup)
.run();
}
8 changes: 4 additions & 4 deletions src/ecs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ pub struct ActuatePlugin;

impl Plugin for ActuatePlugin {
fn build(&self, app: &mut App) {
let rt = Runtime {
let rt = BevyRuntime {
composers: RefCell::new(HashMap::new()),
};

Expand Down Expand Up @@ -102,7 +102,7 @@ struct RuntimeComposer {
composer: Composer,
}

struct Runtime {
struct BevyRuntime {
composers: RefCell<HashMap<Entity, RuntimeComposer>>,
}

Expand Down Expand Up @@ -161,7 +161,7 @@ where
let content = composition.content.take().unwrap();
let target = composition.target.unwrap_or(entity);

let rt = world.non_send_resource_mut::<Runtime>();
let rt = world.non_send_resource_mut::<BevyRuntime>();

rt.composers.borrow_mut().insert(
entity,
Expand Down Expand Up @@ -237,7 +237,7 @@ fn compose(world: &mut World) {
.get_resource::<EventLoopProxyWrapper<WakeUp>>()
.unwrap())
.clone();
let rt = &mut *world.non_send_resource_mut::<Runtime>();
let rt = &mut *world.non_send_resource_mut::<BevyRuntime>();
let mut composers = rt.composers.borrow_mut();
for rt_composer in composers.values_mut() {
let waker = Waker::from(Arc::new(RuntimeWaker {
Expand Down
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ pub mod prelude {
#[cfg(feature = "material")]
#[cfg_attr(docsrs, doc(cfg(feature = "material")))]
pub use crate::ui::material::{
button, container, material_ui, radio_button, text, Button, MaterialUi, RadioButton, Theme,
TypographyKind, TypographyStyleKind,
button, container, material_ui, radio_button, switch, text, Button, MaterialUi,
RadioButton, Switch, Theme, TypographyKind, TypographyStyleKind,
};
}

Expand Down Expand Up @@ -403,7 +403,7 @@ impl<'a, T> Signal<'a, T> {
ptr: me.value as *const _ as _,
map_fn: f as _,
deref_fn: |ptr, g| {
// Safety: `f` is guranteed to be a valid function pointer.
// Safety: `f` is guaranteed to be a valid function pointer.
unsafe {
let g: fn(&T) -> &U = mem::transmute(g);
g(&*(ptr as *const T))
Expand Down Expand Up @@ -494,7 +494,7 @@ impl<'a, T: 'static> SignalMut<'a, T> {
}
}

/// Queue an update to this value wtihout triggering an update.
/// Queue an update to this value without triggering an update.
pub fn with(me: Self, f: impl FnOnce(&mut T) + Send + 'static) {
let cell = UnsafeWrap(Some(f));
let ptr = UnsafeWrap(me.ptr);
Expand Down
6 changes: 6 additions & 0 deletions src/ui/material/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ pub use self::radio::{radio_button, RadioButton};
mod ui;
pub use self::ui::{material_ui, MaterialUi};

mod switch;
pub use self::switch::{switch, Switch};

// mod slider;
// pub use self::slider::{slider, Slider};

/// Text composables.
pub mod text;

Expand Down
6 changes: 3 additions & 3 deletions src/ui/material/radio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ impl Compose for RadioButton<'_> {

let size = Val::Px(cx.me().outer_radius * 2.);
let inner_size = Val::Px(cx.me().inner_radius * 2.);
let offset = Val::Px((cx.me().outer_radius - cx.me().inner_radius) - 2.);
let padding = Val::Px((cx.me().outer_radius - cx.me().inner_radius) - 2.);
let padding_rect = UiRect::all(padding);

cx.me()
.modifier
Expand All @@ -79,6 +80,7 @@ impl Compose for RadioButton<'_> {
width: size,
height: size,
border: UiRect::all(Val::Px(cx.me().border_width)),
padding: padding_rect,
..Default::default()
},
BorderRadius::MAX,
Expand All @@ -96,8 +98,6 @@ impl Compose for RadioButton<'_> {
Node {
width: inner_size,
height: inner_size,
top: offset,
left: offset,

..Default::default()
},
Expand Down
122 changes: 122 additions & 0 deletions src/ui/material/switch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use crate::ui::material::Theme;
use crate::{
compose::Compose,
ecs::spawn,
ecs::{Modifier, Modify},
use_context, Data, Scope,
};
use bevy_color::Color;
use bevy_ui::{BackgroundColor, BorderColor, BorderRadius, BoxShadow, Node, UiRect, Val};

/// Create a material UI switch.
pub fn switch<'a>() -> Switch<'a> {
Switch {
is_enabled: true,
inner_radius: 10.,
outer_radius: 20.,
border_width: 2.,
elevation: 0.,
modifier: Modifier::default(),
}
}

/// Material UI radio button.
#[derive(Clone, Debug, Data)]
#[actuate(path = "crate")]
pub struct Switch<'a> {
is_enabled: bool,
inner_radius: f32,
outer_radius: f32,
border_width: f32,
elevation: f32,
modifier: Modifier<'a>,
}

impl Switch<'_> {
/// Set the enabled state of this radio button.
pub fn is_enabled(mut self, is_enabled: bool) -> Self {
self.is_enabled = is_enabled;
self
}

/// Set the inner radius of this radio button.
pub fn inner_radius(mut self, inner_radius: f32) -> Self {
self.inner_radius = inner_radius;
self
}

/// Set the outer radius of this radio button.
pub fn outer_radius(mut self, outer_radius: f32) -> Self {
self.outer_radius = outer_radius;
self
}

/// Set the border width of this radio button.
pub fn border_width(mut self, border_width: f32) -> Self {
self.border_width = border_width;
self
}

/// Set the elevation of this radio button.
pub fn elevation(mut self, elevation: f32) -> Self {
self.elevation = elevation;
self
}
}

impl Compose for Switch<'_> {
fn compose(cx: Scope<Self>) -> impl Compose {
let theme = use_context::<Theme>(&cx).cloned().unwrap_or_default();

let height = Val::Px(cx.me().outer_radius * 2.);
let width = Val::Px(cx.me().outer_radius * 3.);
let knob_size = Val::Px(cx.me().inner_radius * 2.);
let padding = (cx.me().outer_radius - cx.me().inner_radius) - 2.;
let padding_right = padding + 2. * cx.me().inner_radius;
let mut padding_rect = UiRect::all(Val::Px(padding));
padding_rect.right = Val::Px(padding_right);
let offset_left_val = if cx.me().is_enabled {
Val::Percent(0.)
} else {
Val::Percent(100.)
};

cx.me()
.modifier
.apply(spawn((
Node {
width,
height,
border: UiRect::all(Val::Px(cx.me().border_width)),
padding: padding_rect,
..Default::default()
},
BorderRadius::MAX,
BorderColor(theme.colors.primary),
BoxShadow {
color: Color::srgba(0., 0., 0., 0.12 * cx.me().elevation),
x_offset: Val::Px(0.),
y_offset: Val::Px(1.),
spread_radius: Val::Px(0.),
blur_radius: Val::Px(3. * cx.me().elevation),
},
)))
.content(Some(spawn((
Node {
width: knob_size,
height: knob_size,
left: offset_left_val,

..Default::default()
},
BackgroundColor(theme.colors.primary),
BorderRadius::MAX,
))))
}
}

impl<'a> Modify<'a> for Switch<'a> {
fn modifier(&mut self) -> &mut Modifier<'a> {
&mut self.modifier
}
}