use crate::{
KnobAngleRange,
style::{default_colors, text_marks, tick_marks},
};
use iced::Color;
pub use iced::widget::canvas::{Canvas, LineCap};
#[derive(Debug, Clone)]
pub enum Appearance {
Circle(CircleAppearance),
Arc(ArcAppearance),
ArcBipolar(ArcBipolarAppearance),
}
#[derive(Debug, Clone)]
pub enum StyleLength {
Scaled(f32),
Fixed(f32),
}
impl StyleLength {
#[inline]
pub fn from_knob_diameter(&self, knob_diameter: f32) -> f32 {
match self {
StyleLength::Scaled(scale) => knob_diameter * *scale,
StyleLength::Fixed(units) => *units,
}
}
}
#[derive(Debug, Clone)]
pub struct CircleNotch {
pub color: Color,
pub border_width: f32,
pub border_color: Color,
pub diameter: StyleLength,
pub offset: StyleLength,
}
#[derive(Debug, Clone)]
pub struct LineNotch {
pub color: Color,
pub width: StyleLength,
pub length: StyleLength,
pub cap: LineCap,
pub offset: StyleLength,
}
#[derive(Debug, Clone)]
pub enum NotchShape {
None,
Circle(CircleNotch),
Line(LineNotch),
}
#[derive(Debug, Clone)]
pub struct CircleAppearance {
pub color: Color,
pub border_width: f32,
pub border_color: Color,
pub notch: NotchShape,
}
impl Default for CircleAppearance {
fn default() -> Self {
CircleAppearance {
color: default_colors::LIGHT_BACK,
border_width: 1.0,
border_color: default_colors::BORDER,
notch: NotchShape::Circle(CircleNotch {
color: default_colors::BORDER,
border_width: 0.0,
border_color: Color::TRANSPARENT,
diameter: StyleLength::Scaled(0.17),
offset: StyleLength::Scaled(0.15),
}),
}
}
}
#[derive(Debug, Clone)]
pub struct ArcAppearance {
pub width: StyleLength,
pub empty_color: Color,
pub filled_color: Color,
pub notch: NotchShape,
pub cap: LineCap,
}
#[derive(Debug, Clone)]
pub struct ArcBipolarAppearance {
pub width: StyleLength,
pub empty_color: Color,
pub left_filled_color: Color,
pub right_filled_color: Color,
pub notch_center: NotchShape,
pub notch_left_right: Option<(NotchShape, NotchShape)>,
pub cap: LineCap,
}
#[derive(Debug, Copy, Clone)]
pub struct ValueArcAppearance {
pub width: f32,
pub offset: f32,
pub empty_color: Option<Color>,
pub left_filled_color: Color,
pub right_filled_color: Option<Color>,
pub cap: LineCap,
}
#[derive(Debug, Copy, Clone)]
pub struct ModRangeArcAppearance {
pub width: f32,
pub offset: f32,
pub empty_color: Option<Color>,
pub filled_color: Color,
pub filled_inverse_color: Color,
pub cap: LineCap,
}
#[derive(Debug, Clone)]
pub struct TickMarksAppearance {
pub style: tick_marks::Appearance,
pub offset: f32,
}
#[derive(Debug, Clone)]
pub struct TextMarksAppearance {
pub style: text_marks::Appearance,
pub offset: f32,
pub h_char_offset: f32,
pub v_offset: f32,
}
impl std::default::Default for TextMarksAppearance {
fn default() -> Self {
Self {
style: text_marks::Appearance::default(),
offset: 15.0,
h_char_offset: 3.0,
v_offset: -0.75,
}
}
}
pub trait StyleSheet {
type Style;
fn active(&self, style: &Self::Style) -> Appearance;
fn hovered(&self, style: &Self::Style) -> Appearance;
fn dragging(&self, style: &Self::Style) -> Appearance;
fn angle_range(&self, _style: &Self::Style) -> KnobAngleRange {
KnobAngleRange::default()
}
fn tick_marks_appearance(&self, _style: &Self::Style) -> Option<TickMarksAppearance> {
None
}
fn value_arc_appearance(&self, _style: &Self::Style) -> Option<ValueArcAppearance> {
None
}
fn mod_range_arc_appearance(&self, _style: &Self::Style) -> Option<ModRangeArcAppearance> {
None
}
fn mod_range_arc_appearance_2(&self, _style: &Self::Style) -> Option<ModRangeArcAppearance> {
None
}
fn text_marks_appearance(&self, _style: &Self::Style) -> Option<TextMarksAppearance> {
None
}
}
#[derive(Default)]
pub enum Knob {
#[default]
Default,
Custom(Box<dyn StyleSheet<Style = iced::Theme>>),
}
impl<S> From<S> for Knob
where
S: 'static + StyleSheet<Style = iced::Theme>,
{
fn from(val: S) -> Self {
Knob::Custom(Box::new(val))
}
}
impl StyleSheet for iced::Theme {
type Style = Knob;
fn active(&self, style: &Self::Style) -> Appearance {
match style {
Knob::Default => Appearance::Circle(Default::default()),
Knob::Custom(custom) => custom.active(self),
}
}
fn hovered(&self, style: &Self::Style) -> Appearance {
match style {
Knob::Default => Appearance::Circle(CircleAppearance {
color: default_colors::KNOB_BACK_HOVER,
..Default::default()
}),
Knob::Custom(custom) => custom.hovered(self),
}
}
fn dragging(&self, style: &Self::Style) -> Appearance {
match style {
Knob::Default => self.hovered(style),
Knob::Custom(custom) => custom.dragging(self),
}
}
fn angle_range(&self, style: &Self::Style) -> KnobAngleRange {
match style {
Knob::Default => KnobAngleRange::default(),
Knob::Custom(custom) => custom.angle_range(self),
}
}
fn tick_marks_appearance(&self, style: &Self::Style) -> Option<TickMarksAppearance> {
match style {
Knob::Default => Some(TickMarksAppearance {
style: tick_marks::Appearance {
tier_1: tick_marks::Shape::Circle {
diameter: 4.0,
color: default_colors::TICK_TIER_1,
},
tier_2: tick_marks::Shape::Circle {
diameter: 2.0,
color: default_colors::TICK_TIER_2,
},
tier_3: tick_marks::Shape::Circle {
diameter: 2.0,
color: default_colors::TICK_TIER_3,
},
},
offset: 3.5,
}),
Knob::Custom(custom) => custom.tick_marks_appearance(self),
}
}
fn value_arc_appearance(&self, style: &Self::Style) -> Option<ValueArcAppearance> {
match style {
Knob::Default => None,
Knob::Custom(custom) => custom.value_arc_appearance(self),
}
}
fn mod_range_arc_appearance(&self, style: &Self::Style) -> Option<ModRangeArcAppearance> {
match style {
Knob::Default => None,
Knob::Custom(custom) => custom.mod_range_arc_appearance(self),
}
}
fn mod_range_arc_appearance_2(&self, style: &Self::Style) -> Option<ModRangeArcAppearance> {
match style {
Knob::Default => None,
Knob::Custom(custom) => custom.mod_range_arc_appearance_2(self),
}
}
fn text_marks_appearance(&self, style: &Self::Style) -> Option<TextMarksAppearance> {
match style {
Knob::Default => Some(TextMarksAppearance {
style: Default::default(),
offset: 14.0,
h_char_offset: 3.0,
v_offset: -0.75,
}),
Knob::Custom(custom) => custom.text_marks_appearance(self),
}
}
}