|
|
|
@ -1,12 +1,13 @@
|
|
|
|
// TODO:
|
|
|
|
// TODO:
|
|
|
|
// * Debug Panel
|
|
|
|
|
|
|
|
// * Describe cell I am hovering over (Note, Octave, etc)
|
|
|
|
|
|
|
|
// * Count # of cells on the board
|
|
|
|
|
|
|
|
// * Fix tiling repeating
|
|
|
|
// * Fix tiling repeating
|
|
|
|
// * Negative coordinates should not mirror
|
|
|
|
// * Negative coordinates should not mirror
|
|
|
|
// * Fix randomly audio not working
|
|
|
|
// * Fix randomly audio not working
|
|
|
|
// * space -> play/pause sim
|
|
|
|
// * Make click and drag feel better
|
|
|
|
// * m -> un/mute audio
|
|
|
|
// * Show shadow of piece (same tile, just with alpha transparency)
|
|
|
|
|
|
|
|
// * UI widget explaining rules/hotkeys
|
|
|
|
|
|
|
|
// * UI minimize widgets
|
|
|
|
|
|
|
|
// * Start with an interesting pattern
|
|
|
|
|
|
|
|
// * Lock down system scheduling/run_if conditions
|
|
|
|
#![allow(clippy::complexity)]
|
|
|
|
#![allow(clippy::complexity)]
|
|
|
|
// Only because of FromTemplat macros unfortunately...
|
|
|
|
// Only because of FromTemplat macros unfortunately...
|
|
|
|
#![allow(dead_code)]
|
|
|
|
#![allow(dead_code)]
|
|
|
|
@ -83,15 +84,16 @@ fn main() {
|
|
|
|
grid_gizmo,
|
|
|
|
grid_gizmo,
|
|
|
|
update_debug_info_cell_count,
|
|
|
|
update_debug_info_cell_count,
|
|
|
|
update_debug_info_coordinates,
|
|
|
|
update_debug_info_coordinates,
|
|
|
|
|
|
|
|
update_debug_info_active,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
// Ui Controllers
|
|
|
|
// Ui Controllers
|
|
|
|
.add_systems(
|
|
|
|
.add_systems(
|
|
|
|
Update,
|
|
|
|
Update,
|
|
|
|
(
|
|
|
|
(
|
|
|
|
// TODO: Visualize audio play/mute buttons enable/disable
|
|
|
|
toggle_state_visible::<SimulationPlayback>.run_if(state_changed::<SimulationPlayback>),
|
|
|
|
manage_interactive::<SimulationPlayback>,
|
|
|
|
manage_interactive::<SimulationPlayback>,
|
|
|
|
// TODO Visualize simulation run/pause buttons enable/disable
|
|
|
|
toggle_state_visible::<AudioPlayback>.run_if(state_changed::<AudioPlayback>),
|
|
|
|
manage_interactive::<AudioPlayback>,
|
|
|
|
manage_interactive::<AudioPlayback>,
|
|
|
|
update_note_interactivity,
|
|
|
|
update_note_interactivity,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
@ -110,6 +112,7 @@ const SCALE: f32 = 100.0;
|
|
|
|
enum DebugInfo {
|
|
|
|
enum DebugInfo {
|
|
|
|
CellCount,
|
|
|
|
CellCount,
|
|
|
|
Coordinates,
|
|
|
|
Coordinates,
|
|
|
|
|
|
|
|
Active,
|
|
|
|
#[default]
|
|
|
|
#[default]
|
|
|
|
Empty,
|
|
|
|
Empty,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -196,6 +199,43 @@ fn ui_button(button: UiButton) -> impl Scene {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn ui_toggle_button<A: Scene, B: Scene>((button_a, state_a): (UiButton, A), (button_b, state_b): (UiButton, B)) -> impl Scene {
|
|
|
|
|
|
|
|
bsn! {
|
|
|
|
|
|
|
|
@FeathersButton
|
|
|
|
|
|
|
|
Hovered
|
|
|
|
|
|
|
|
Node {
|
|
|
|
|
|
|
|
top: Val::Px(2.5),
|
|
|
|
|
|
|
|
left: Val::Px(2.5),
|
|
|
|
|
|
|
|
margin: UiRect::all(Val::Px(2.5)),
|
|
|
|
|
|
|
|
align_items: AlignItems::Center,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Children [
|
|
|
|
|
|
|
|
Node {
|
|
|
|
|
|
|
|
align_self: AlignSelf::Center,
|
|
|
|
|
|
|
|
justify_self: JustifySelf::Center,
|
|
|
|
|
|
|
|
width: Val::Percent(100.0),
|
|
|
|
|
|
|
|
height: Val::Percent(100.0),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ImageNode {
|
|
|
|
|
|
|
|
image: HandleTemplate::Path(AssetPath::parse(button_a.icon())),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
state_a
|
|
|
|
|
|
|
|
ToggleStateVisible,
|
|
|
|
|
|
|
|
Node {
|
|
|
|
|
|
|
|
align_self: AlignSelf::Center,
|
|
|
|
|
|
|
|
justify_self: JustifySelf::Center,
|
|
|
|
|
|
|
|
width: Val::Percent(100.0),
|
|
|
|
|
|
|
|
height: Val::Percent(100.0),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ImageNode {
|
|
|
|
|
|
|
|
image: HandleTemplate::Path(AssetPath::parse(button_b.icon())),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
state_b
|
|
|
|
|
|
|
|
ToggleStateVisible,
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn the_camera() -> impl Scene {
|
|
|
|
fn the_camera() -> impl Scene {
|
|
|
|
bsn! {
|
|
|
|
bsn! {
|
|
|
|
Camera2d
|
|
|
|
Camera2d
|
|
|
|
@ -305,6 +345,27 @@ fn debug_ui() -> impl Scene {
|
|
|
|
Children [
|
|
|
|
Children [
|
|
|
|
Text("##,##") ThemedText template_value(DebugInfo::Coordinates)
|
|
|
|
Text("##,##") ThemedText template_value(DebugInfo::Coordinates)
|
|
|
|
]
|
|
|
|
]
|
|
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
subpane()
|
|
|
|
|
|
|
|
Node {
|
|
|
|
|
|
|
|
display: Display::Flex,
|
|
|
|
|
|
|
|
flex_direction: FlexDirection::Row,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Children [
|
|
|
|
|
|
|
|
subpane_header() Children [
|
|
|
|
|
|
|
|
Text("Active Cell") ThemedText
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
subpane_body()
|
|
|
|
|
|
|
|
Node {
|
|
|
|
|
|
|
|
display: Display::Flex,
|
|
|
|
|
|
|
|
flex_direction: FlexDirection::Row,
|
|
|
|
|
|
|
|
align_items: AlignItems::Stretch,
|
|
|
|
|
|
|
|
justify_content: JustifyContent::Start,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
text_setup()
|
|
|
|
|
|
|
|
Children [
|
|
|
|
|
|
|
|
Text("Foo/Bar") ThemedText template_value(DebugInfo::Active)
|
|
|
|
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
]
|
|
|
|
@ -362,11 +423,7 @@ fn primary_ui() -> impl Scene {
|
|
|
|
Children [
|
|
|
|
Children [
|
|
|
|
ui_button(UiButton::Power)
|
|
|
|
ui_button(UiButton::Power)
|
|
|
|
ActionSource<Action>(Action::Quit),
|
|
|
|
ActionSource<Action>(Action::Quit),
|
|
|
|
ui_button(UiButton::Pause)
|
|
|
|
ui_toggle_button((UiButton::Pause, bsn! { SimulationPlayback::Pause }), (UiButton::Play, bsn! { SimulationPlayback::Run }))
|
|
|
|
SimulationPlayback::Pause
|
|
|
|
|
|
|
|
ActionSource<SimAction>(SimAction::Toggle),
|
|
|
|
|
|
|
|
ui_button(UiButton::Play)
|
|
|
|
|
|
|
|
SimulationPlayback::Run
|
|
|
|
|
|
|
|
ActionSource<SimAction>(SimAction::Toggle),
|
|
|
|
ActionSource<SimAction>(SimAction::Toggle),
|
|
|
|
ui_button(UiButton::Step)
|
|
|
|
ui_button(UiButton::Step)
|
|
|
|
ActionSource<SimAction>(SimAction::Step),
|
|
|
|
ActionSource<SimAction>(SimAction::Step),
|
|
|
|
@ -378,11 +435,7 @@ fn primary_ui() -> impl Scene {
|
|
|
|
ActionSource<ZoomAction>(ZoomAction::ZoomOut),
|
|
|
|
ActionSource<ZoomAction>(ZoomAction::ZoomOut),
|
|
|
|
ui_button(UiButton::ZoomIn)
|
|
|
|
ui_button(UiButton::ZoomIn)
|
|
|
|
ActionSource<ZoomAction>(ZoomAction::ZoomIn),
|
|
|
|
ActionSource<ZoomAction>(ZoomAction::ZoomIn),
|
|
|
|
ui_button(UiButton::MuteAudio)
|
|
|
|
ui_toggle_button((UiButton::MuteAudio, bsn! { AudioPlayback::Mute }), (UiButton::PlayAudio, bsn! { AudioPlayback::Play }))
|
|
|
|
AudioPlayback::Mute
|
|
|
|
|
|
|
|
ActionSource<AudioAction>(AudioAction::Toggle),
|
|
|
|
|
|
|
|
ui_button(UiButton::PlayAudio)
|
|
|
|
|
|
|
|
AudioPlayback::Play
|
|
|
|
|
|
|
|
ActionSource<AudioAction>(AudioAction::Toggle),
|
|
|
|
ActionSource<AudioAction>(AudioAction::Toggle),
|
|
|
|
]
|
|
|
|
]
|
|
|
|
],
|
|
|
|
],
|
|
|
|
@ -555,7 +608,7 @@ impl Coordinates {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// When the cursor moves, update the Coordiantes
|
|
|
|
/// When the cursor moves, update the Coordinates
|
|
|
|
fn update_grid_position(
|
|
|
|
fn update_grid_position(
|
|
|
|
mut coordinates: ResMut<NextCoordinates>,
|
|
|
|
mut coordinates: ResMut<NextCoordinates>,
|
|
|
|
q_window: Single<&Window>,
|
|
|
|
q_window: Single<&Window>,
|
|
|
|
@ -1171,6 +1224,22 @@ fn update_debug_info_coordinates(
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn update_debug_info_active(
|
|
|
|
|
|
|
|
next_coordinates: Res<NextCoordinates>,
|
|
|
|
|
|
|
|
cells: Query<(&CellPitch, &Coordinates)>,
|
|
|
|
|
|
|
|
mut text: Query<(&DebugInfo, &mut Text)>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
text.iter_mut()
|
|
|
|
|
|
|
|
.filter(|(di, _)| **di == DebugInfo::Active)
|
|
|
|
|
|
|
|
.for_each(|(_, mut t)| {
|
|
|
|
|
|
|
|
if let Some((cp, _c)) = cells.iter().find(|(_cp, c)| **c == next_coordinates.0) {
|
|
|
|
|
|
|
|
*t = Text::new(format!("Note: {:?} | Octave: {}", cp.note, cp.octave));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
*t = Text::new(String::from("N/A"));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
fn update_note_interactivity(
|
|
|
|
fn update_note_interactivity(
|
|
|
|
checked: Query<Entity, (With<Note>, With<Checkbox>, With<Checked>)>,
|
|
|
|
checked: Query<Entity, (With<Note>, With<Checkbox>, With<Checked>)>,
|
|
|
|
mut commands: Commands,
|
|
|
|
mut commands: Commands,
|
|
|
|
@ -1190,3 +1259,19 @@ fn update_note_interactivity(
|
|
|
|
fn pause_simulation(mut next: ResMut<NextState<SimulationPlayback>>) {
|
|
|
|
fn pause_simulation(mut next: ResMut<NextState<SimulationPlayback>>) {
|
|
|
|
next.set(SimulationPlayback::Pause)
|
|
|
|
next.set(SimulationPlayback::Pause)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Component, Debug, FromTemplate)]
|
|
|
|
|
|
|
|
struct ToggleStateVisible;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn toggle_state_visible<S: States + Component>(
|
|
|
|
|
|
|
|
mut q: Query<(&S, &mut Node), With<ToggleStateVisible>>,
|
|
|
|
|
|
|
|
c: Res<State<S>>
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
q.iter_mut().for_each(|(s, mut node)| {
|
|
|
|
|
|
|
|
node.display = if s == c.get() {
|
|
|
|
|
|
|
|
Display::None
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
Display::Flex
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|