use bevy::{
ecs::{component::Component, system::Resource},
reflect::Reflect,
};
use bevy_inspector_egui::inspector_options::{InspectorOptions, ReflectInspectorOptions};
use serde::{Deserialize, Serialize};
#[derive(
Resource,
Debug,
Component,
PartialEq,
Eq,
Clone,
Copy,
Serialize,
Deserialize,
Reflect,
InspectorOptions,
)]
#[reflect(InspectorOptions)]
pub struct Volume {
#[inspector(min = 0, max = 100)]
pub value: u32,
pub muted: bool,
}
impl Volume {
pub const MIN: u32 = 0;
pub const MAX: u32 = 100;
pub fn set(&mut self, value: impl Into<u32>) {
self.value = value.into().clamp(Self::MIN, Self::MAX);
}
pub fn increment(&mut self) {
let new_value = self.value + 10;
if new_value > Self::MAX {
self.value = Self::MIN;
} else {
self.value = new_value;
}
}
#[must_use]
pub fn raw_volume<T>(&self) -> T
where
T: std::convert::From<u32>,
{
std::convert::From::from(self.value)
}
#[must_use]
pub fn volume<T>(&self) -> T
where
T: std::convert::From<u32>,
{
if self.muted {
std::convert::From::from(0)
} else {
std::convert::From::from(self.value)
}
}
#[must_use]
pub const fn is_muted(&self) -> bool {
self.muted
}
pub fn mute(&mut self) {
self.muted = true;
}
pub fn unmute(&mut self) {
self.muted = false;
}
}
impl std::default::Default for Volume {
fn default() -> Self {
Self {
value: 50,
muted: false,
}
}
}
impl std::fmt::Display for Volume {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.muted {
write!(f, "muted")
} else {
write!(f, "{}%", self.value)
}
}
}
impl From<Volume> for String {
fn from(val: Volume) -> Self {
if val.muted {
"muted".to_string()
} else {
format!("{}%", val.value)
}
}
}
impl From<u64> for Volume {
fn from(value: u64) -> Self {
let Ok(clamped_value) = u32::try_from(value) else {
return Self {
value: Self::MAX,
muted: false,
};
};
let clamped_value = clamped_value.clamp(Self::MIN, Self::MAX);
Self {
value: clamped_value,
muted: false,
}
}
}
impl From<u32> for Volume {
fn from(value: u32) -> Self {
let clamped_value = value.clamp(Self::MIN, Self::MAX);
Self {
value: clamped_value,
muted: false,
}
}
}
impl From<u16> for Volume {
fn from(value: u16) -> Self {
let clamped_value = u32::from(value).clamp(Self::MIN, Self::MAX);
Self {
value: clamped_value,
muted: false,
}
}
}
impl From<u8> for Volume {
fn from(value: u8) -> Self {
let clamped_value = u32::from(value).clamp(Self::MIN, Self::MAX);
Self {
value: clamped_value,
muted: false,
}
}
}
impl From<i64> for Volume {
fn from(value: i64) -> Self {
if value < 0 {
return Self {
value: 0,
muted: false,
};
}
#[allow(clippy::cast_sign_loss)]
let Ok(clamped_value) = u32::try_from(value) else {
return Self {
value: Self::MAX,
muted: false,
};
};
let clamped_value = clamped_value.clamp(Self::MIN, Self::MAX);
Self {
value: clamped_value,
muted: false,
}
}
}
impl From<i32> for Volume {
fn from(value: i32) -> Self {
if value < 0 {
return Self {
value: 0,
muted: false,
};
}
#[allow(clippy::cast_sign_loss)]
let clamped_value = (value as u32).min(Self::MAX);
Self {
value: clamped_value,
muted: false,
}
}
}
impl From<i16> for Volume {
fn from(value: i16) -> Self {
if value < 0 {
return Self {
value: 0,
muted: false,
};
}
#[allow(clippy::cast_sign_loss)]
let clamped_value = (value as u32).min(Self::MAX);
Self {
value: clamped_value,
muted: false,
}
}
}
impl From<i8> for Volume {
fn from(value: i8) -> Self {
if value < 0 {
return Self {
value: 0,
muted: false,
};
}
#[allow(clippy::cast_sign_loss)]
let clamped_value = (value as u32).min(Self::MAX);
Self {
value: clamped_value,
muted: false,
}
}
}
impl From<f32> for Volume {
fn from(value: f32) -> Self {
#[allow(clippy::cast_possible_truncation)]
let mut clamped_value = (value * 100.0) as i32;
if clamped_value < 0 {
clamped_value = 0;
}
#[allow(clippy::cast_sign_loss)]
let clamped_value = (clamped_value as u32).min(Self::MAX);
Self {
value: clamped_value,
muted: false,
}
}
}
impl From<f64> for Volume {
fn from(value: f64) -> Self {
#[allow(clippy::cast_possible_truncation)]
let mut clamped_value = (value * 100.0) as i32;
if clamped_value < 0 {
clamped_value = 0;
}
#[allow(clippy::cast_sign_loss)]
let clamped_value = (clamped_value as u32).min(Self::MAX);
Self {
value: clamped_value,
muted: false,
}
}
}