Created
July 19, 2024 19:29
-
-
Save ChristopherBiscardi/0e29ac6853c1ba9013295a0085a837e4 to your computer and use it in GitHub Desktop.
A calculator in bevy! (codegolf)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::ops::Deref; | |
use bevy::{color::palettes::tailwind::*, prelude::*}; | |
use calc::*; | |
use itertools::Itertools; | |
use rust_decimal::prelude::*; | |
fn main() { | |
App::new() | |
.insert_resource(ClearColor(SLATE_950.into())) | |
.add_plugins(DefaultPlugins) | |
.add_systems(Startup, startup) | |
.add_systems(Update, button_system) | |
.observe(calculate) | |
.run(); | |
} | |
fn calculate( | |
trigger: Trigger<PressEvent>, | |
mut display: Local<String>, | |
mut text_query: Query<&mut Text, With<Output>>, | |
) { | |
match trigger.event().0.deref() { | |
"C" => { | |
*display = "".to_string(); | |
} | |
"=" => { | |
let Ok(result) = Context::<f64>::default() | |
.evaluate(&display) | |
else { | |
*display = "error".to_string(); | |
return; | |
}; | |
if let Some(result) = Decimal::from_f64( | |
(result * 100.).round() / 100., | |
) { | |
*display = result.normalize().to_string(); | |
} else { | |
*display = result.to_string(); | |
} | |
} | |
x => { | |
display.push_str(x); | |
} | |
} | |
for mut text in &mut text_query { | |
text.sections[0].value = | |
display.chars().tail(11).collect::<String>(); | |
} | |
} | |
#[derive(Component)] | |
struct Output; | |
fn startup(mut commands: Commands) { | |
commands.spawn(Camera2dBundle::default()); | |
let container = commands | |
.spawn(NodeBundle { | |
style: Style { | |
display: Display::Grid, | |
grid_template_columns: | |
RepeatedGridTrack::auto(4), | |
margin: UiRect::all(Val::Auto), | |
..default() | |
}, | |
..default() | |
}) | |
.id(); | |
let items = vec![ | |
"C", "", "7", "8", "9", "/", "4", "5", "6", "*", | |
"1", "2", "3", "-", "0", ".", "=", "+", | |
]; | |
for item in items { | |
let button = commands | |
.spawn(ButtonBundle { | |
style: Style { | |
grid_column: GridPlacement::span( | |
if item == "" { 3 } else { 1 }, | |
), | |
border: UiRect::all(Val::Px(1.)), | |
padding: UiRect::all(Val::Px(20.)), | |
margin: UiRect::all(Val::Px(5.)), | |
..default() | |
}, | |
border_radius: BorderRadius::all( | |
if item == "" { | |
Val::Px(0.) | |
} else { | |
Val::Px(5.) | |
}, | |
), | |
border_color: BorderColor(if item == "" { | |
SKY_950.into() | |
} else { | |
SLATE_400.into() | |
}), | |
..default() | |
}) | |
.with_children(|builder| { | |
let mut b = builder.spawn(TextBundle { | |
text: Text::from_section( | |
item, | |
TextStyle::default(), | |
), | |
..default() | |
}); | |
if item == "" { | |
b.insert(Output); | |
} | |
}) | |
.id(); | |
commands.entity(container).add_child(button); | |
} | |
} | |
#[derive(Event)] | |
struct PressEvent(String); | |
const NORMAL_BUTTON: Srgba = SLATE_500; | |
const HOVERED_BUTTON: Srgba = SLATE_400; | |
const PRESSED_BUTTON: Srgba = GREEN_400; | |
fn button_system( | |
mut commands: Commands, | |
mut interaction_query: Query< | |
( | |
&Interaction, | |
&mut BackgroundColor, | |
&Children, | |
), | |
(Changed<Interaction>, With<Button>), | |
>, | |
text_query: Query<&Text>, | |
) { | |
for (interaction, mut color, children) in | |
&mut interaction_query | |
{ | |
let text = text_query.get(children[0]).unwrap(); | |
match *interaction { | |
Interaction::Pressed => { | |
*color = PRESSED_BUTTON.into(); | |
commands.trigger(PressEvent( | |
text.sections[0].value.to_string(), | |
)); | |
} | |
Interaction::Hovered => { | |
*color = HOVERED_BUTTON.into(); | |
} | |
Interaction::None => { | |
*color = NORMAL_BUTTON.into(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment