use crate::event::Rect;
use crate::types::{Color, WidgetId};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Spinner {
pub id: WidgetId,
#[serde(default)]
pub label: String,
#[serde(default)]
pub frame_idx: usize,
#[serde(default)]
pub accent: Option<Color>,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SpinnerMeasure {
pub width: f32,
pub height: f32,
}
impl SpinnerMeasure {
pub fn new(width: f32, height: f32) -> Self {
Self { width, height }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SpinnerHit {
Body(WidgetId),
Empty,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct SpinnerLayout {
pub bounds: Rect,
}
impl SpinnerLayout {
pub fn hit_test(&self, x: f32, y: f32, id: &WidgetId) -> SpinnerHit {
if x >= self.bounds.x
&& x < self.bounds.x + self.bounds.width
&& y >= self.bounds.y
&& y < self.bounds.y + self.bounds.height
{
SpinnerHit::Body(*id)
} else {
SpinnerHit::Empty
}
}
}
impl Spinner {
pub fn layout(&self, origin_x: f32, origin_y: f32, measure: SpinnerMeasure) -> SpinnerLayout {
SpinnerLayout {
bounds: Rect::new(origin_x, origin_y, measure.width, measure.height),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn spinner_layout_bounds() {
let s = Spinner {
id: WidgetId::new("installing"),
label: "Installing rust-analyzer…".to_string(),
frame_idx: 42,
accent: None,
};
let layout = s.layout(10.0, 20.0, SpinnerMeasure::new(200.0, 16.0));
assert_eq!(layout.bounds.x, 10.0);
assert_eq!(layout.bounds.y, 20.0);
assert_eq!(layout.bounds.width, 200.0);
match layout.hit_test(100.0, 28.0, &s.id) {
SpinnerHit::Body(id) => assert_eq!(id.as_str(), "installing"),
_ => panic!(),
}
assert_eq!(layout.hit_test(500.0, 28.0, &s.id), SpinnerHit::Empty);
}
}