use rlvgl_core::widget::Color;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MeterColorId {
Safe,
Nominal,
Caution,
Hot,
Over,
}
#[derive(Debug, Clone, Copy)]
pub struct Palette {
pub safe: Color,
pub nominal: Color,
pub caution: Color,
pub hot: Color,
pub over: Color,
}
impl Palette {
pub const fn color(&self, id: MeterColorId) -> Color {
match id {
MeterColorId::Safe => self.safe,
MeterColorId::Nominal => self.nominal,
MeterColorId::Caution => self.caution,
MeterColorId::Hot => self.hot,
MeterColorId::Over => self.over,
}
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct SecondaryColors {
pub background: Option<Color>,
pub frame: Option<Color>,
pub scale_text: Option<Color>,
pub minor_tick: Option<Color>,
pub major_tick: Option<Color>,
pub needle: Option<Color>,
pub needle_pivot: Option<Color>,
pub led_off: Option<Color>,
pub peak_hold: Option<Color>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Orientation {
Horizontal,
Vertical,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MeterType {
Bargraph,
Needle,
Numeric,
LufsGauge,
}
#[derive(Debug, Clone, Copy)]
pub struct Layout {
pub orientation: Orientation,
pub aspect_ratio: f32,
pub led_count: u32,
pub peak_hold_ms: f32,
}
#[derive(Debug, Clone, Copy)]
pub struct Zone {
pub from_db: f32,
pub to_db: f32,
pub color: MeterColorId,
}
#[derive(Debug, Clone, Copy)]
pub struct TickLabel {
pub value: f32,
pub label: &'static str,
}
#[derive(Debug, Clone, Copy)]
pub struct Scale {
pub id: &'static str,
pub label_units: &'static str,
pub range_min_db: f32,
pub range_max_db: f32,
pub pivot_value: f32,
pub pivot_label: &'static str,
pub pivot_input_dbfs: f32,
pub calibration_offset_db: Option<f32>,
pub majors: &'static [f32],
pub minors_per_major_division: u32,
pub tick_labels: &'static [TickLabel],
pub zones: &'static [Zone],
}
#[derive(Debug, Clone, Copy)]
pub struct SkinAssets {
pub led_segment_on_png: Option<&'static [u8]>,
pub led_segment_off_png: Option<&'static [u8]>,
pub needle_svg: Option<&'static [u8]>,
pub bezel_svg: Option<&'static [u8]>,
pub faceplate_png: Option<&'static [u8]>,
}
impl SkinAssets {
pub const EMPTY: Self = Self {
led_segment_on_png: None,
led_segment_off_png: None,
needle_svg: None,
bezel_svg: None,
faceplate_png: None,
};
pub const fn any_present(&self) -> bool {
self.led_segment_on_png.is_some()
|| self.led_segment_off_png.is_some()
|| self.needle_svg.is_some()
|| self.bezel_svg.is_some()
|| self.faceplate_png.is_some()
}
}
#[derive(Debug, Clone, Copy)]
pub struct Skin {
pub id: &'static str,
pub title: &'static str,
pub scale: &'static Scale,
pub default_ballistic: rlvgl_audio_meters_core::Ballistic,
pub meter_type: MeterType,
pub palette: Palette,
pub secondary: SecondaryColors,
pub layout: Layout,
pub assets: SkinAssets,
}
impl Scale {
#[inline]
pub fn dbfs_to_scale_units(&self, dbfs: f32) -> f32 {
dbfs + (self.pivot_value - self.pivot_input_dbfs)
}
pub fn label_for_major(&self, value: f32) -> Option<&'static str> {
for t in self.tick_labels {
if (t.value - value).abs() < 1e-3 {
return Some(t.label);
}
}
None
}
pub fn zone_color_for(&self, scale_value: f32) -> MeterColorId {
for z in self.zones {
if scale_value < z.to_db {
return z.color;
}
}
self.zones
.last()
.map(|z| z.color)
.unwrap_or(MeterColorId::Safe)
}
}
#[inline]
pub const fn rgb(r: u8, g: u8, b: u8) -> Color {
Color(r, g, b, 0xff)
}
#[inline]
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Color {
Color(r, g, b, a)
}