use bevy::prelude::*;
use bevy::ui_widgets::ValueChange;
use crate::binding::BindingSettings;
use crate::choice::ChoiceValue;
use crate::model::{INTERFACE_SIZE_STEPS, PAD_STYLES, TEXT_SIZE_STEPS, nearest_step};
use crate::scale::UiScaleSettings;
use crate::skin::{GooeySkin, SkinPreset};
#[derive(Component, Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum OptionRow {
TextSize,
InterfaceSize,
PadStyle,
SkinPreset,
}
impl OptionRow {
pub(crate) fn options(self) -> Vec<String> {
match self {
Self::TextSize => TEXT_SIZE_STEPS.iter().map(|&step| percent(step)).collect(),
Self::InterfaceSize => INTERFACE_SIZE_STEPS
.iter()
.map(|&step| percent(step))
.collect(),
Self::PadStyle => PAD_STYLES
.iter()
.map(|style| style.name().to_owned())
.collect(),
Self::SkinPreset => SkinPreset::ALL
.iter()
.map(|preset| preset.name().to_owned())
.collect(),
}
}
}
fn percent(step: f32) -> String {
format!("{:.0}%", step * 100.0)
}
pub(crate) fn option_on_change(
change: On<ValueChange<usize>>,
rows: Query<&OptionRow>,
skin: Option<ResMut<GooeySkin>>,
scale: Option<ResMut<UiScaleSettings>>,
binding: Option<ResMut<BindingSettings>>,
) {
let Ok(row) = rows.get(change.source) else {
return;
};
match row {
OptionRow::TextSize => {
if let (Some(mut skin), Some(&step)) = (skin, TEXT_SIZE_STEPS.get(change.value)) {
skin.text_scale = step;
}
}
OptionRow::InterfaceSize => {
if let (Some(mut scale), Some(&step)) = (scale, INTERFACE_SIZE_STEPS.get(change.value))
{
scale.scale = step;
}
}
OptionRow::PadStyle => {
if let (Some(mut binding), Some(&style)) = (binding, PAD_STYLES.get(change.value)) {
binding.pad_style = style;
}
}
OptionRow::SkinPreset => {
if let (Some(mut skin), Some(preset)) = (skin, SkinPreset::ALL.get(change.value)) {
let next = skin.clone().with_colours_of(&preset.skin());
skin.set_if_neq(next);
}
}
}
}
pub fn update_option_rows(
skin: Res<GooeySkin>,
scale: Option<Res<UiScaleSettings>>,
binding: Res<BindingSettings>,
mut rows: Query<(Ref<OptionRow>, &mut ChoiceValue)>,
) {
for (row, mut value) in &mut rows {
let index = match *row {
OptionRow::TextSize => (skin.is_changed() || row.is_added())
.then(|| nearest_step(&TEXT_SIZE_STEPS, skin.text_scale)),
OptionRow::SkinPreset => (skin.is_changed() || row.is_added()).then(|| {
let preset = SkinPreset::of(&skin);
SkinPreset::ALL
.iter()
.position(|&candidate| candidate == preset)
.unwrap_or(0)
}),
OptionRow::InterfaceSize => scale
.as_ref()
.filter(|scale| scale.is_changed() || row.is_added())
.map(|scale| nearest_step(&INTERFACE_SIZE_STEPS, scale.scale)),
OptionRow::PadStyle => (binding.is_changed() || row.is_added()).then(|| {
PAD_STYLES
.iter()
.position(|&style| style == binding.pad_style)
.unwrap_or(0)
}),
};
if let Some(index) = index {
value.set_if_neq(ChoiceValue(index));
}
}
}