use iced::canvas::event::Status; use iced::Font; use iced::canvas::Text; use iced::canvas::Stroke; use iced::Size; use iced::Point; use iced::canvas::Path; use iced::canvas::Frame; use iced::canvas::Geometry; use iced::canvas::Cursor; use iced::Element; use crate::app::Message; use iced::canvas::Program; use iced::mouse; use iced::Color; use iced::Rectangle; use iced::Length; use iced::alignment::{Vertical, Horizontal}; use iced::widget::canvas::{self, Canvas}; /* RYGCBM const COLORS: [Color; 6] = [ Color { r: 1., g: 0., b: 0., a: 1. }, Color { r: 1., g: 1., b: 0., a: 1. }, Color { r: 0., g: 1., b: 0., a: 1. }, Color { r: 0., g: 1., b: 1., a: 1. }, Color { r: 0., g: 0., b: 1., a: 1. }, Color { r: 1., g: 0., b: 1., a: 1. }, ];*/ #[allow(clippy::eq_op)] const COLORS: [Color; 6] = [ Color { r: 255./255., g: 129./255., b: 126./255., a: 1. }, Color { r: 239./255., g: 190./255., b: 125./255., a: 1. }, Color { r: 233./255., g: 236./255., b: 107./255., a: 1. }, Color { r: 119./255., g: 221./255., b: 119./255., a: 1. }, Color { r: 139./255., g: 211./255., b: 230./255., a: 1. }, Color { r: 177./255., g: 162./255., b: 202./255., a: 1. }, ]; const MAX_TICKS: usize = 900; const FONT_MR_PIXEL: Font = Font::External { name: "Mister Pixel", bytes: include_bytes!("../fonts/mister-pixel/mister-pixel.otf"), }; pub fn view_fileselector(tick: usize) -> Element<'static, Message> { Canvas::new(tick) .width(Length::Fill) .height(Length::Fill) .into() } impl Program for usize { fn draw(&self, bounds: Rectangle, _cursor: Cursor) -> Vec { let tick = self; let offset_per_index = MAX_TICKS / COLORS.len(); const TEXT_RECT_W: f32 = 350.; const TEXT_RECT_H: f32 = 50.; const RECT_RATIO: f32 = TEXT_RECT_W / TEXT_RECT_H; let text_rect_scale = TEXT_RECT_W / bounds.width; let text_rect: (Point, Size) = centered_rectangle(&bounds, RECT_RATIO, text_rect_scale); let text_rect_far_point = Point { x: text_rect.0.x + text_rect.1.width, y: text_rect.0.y + text_rect.1.height, }; let bound_far_point: Point = Point { x: bounds.x + bounds.width, y: bounds.y + bounds.height, }; let mut frame = Frame::new(bounds.size()); frame.fill_rectangle( Point::new(bounds.x, bounds.y), Size::new(bounds.width, bounds.height), Color::WHITE, ); COLORS.iter() .enumerate() .map(|(index, color)| { let size = ((tick + offset_per_index * index) % MAX_TICKS) as f32 / MAX_TICKS as f32; let top_left = interpolate(text_rect.0, Point::ORIGIN, size); let far_corner = interpolate(text_rect_far_point, bound_far_point, size); let rect_size = Size::new(far_corner.x - top_left.x, far_corner.y - top_left.y); (Path::rectangle(top_left, rect_size), color) }) .for_each(|(rect, color)| frame.stroke( &rect, Stroke::default() .with_color(*color) .with_width(5.) ) ); frame.fill_text( Text { content: String::from("select a song to start"), horizontal_alignment: Horizontal::Center, vertical_alignment: Vertical::Center, size: 32., color: Color::WHITE, font: FONT_MR_PIXEL, position: Point::new( bounds.x + bounds.width * 0.5, bounds.y + bounds.height * 0.5, ), } ); frame.fill( &Path::rectangle(text_rect.0, text_rect.1), Color::BLACK, ); frame.stroke( &Path::rectangle(text_rect.0, text_rect.1), Stroke::default() .with_color(Color::BLACK) .with_width(2.) ); vec![frame.into_geometry()] } fn update( &mut self, event: canvas::Event, _: Rectangle, _: Cursor ) -> (Status, Option) { match event { canvas::Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) => { (Status::Captured, Some(Message::PromptForFile)) }, _ => (Status::Ignored, None), } } } fn centered_rectangle(bounds: &Rectangle, ratio: f32, scale: f32) -> (Point, Size) { let center_x = bounds.x + 0.5 * bounds.width; let center_y = bounds.y + 0.5 * bounds.height; let width = bounds.width * scale; let height = width / ratio; let top_x = center_x - width * 0.5; let top_y = center_y - height * 0.5; ( Point::new(top_x, top_y), Size::new(width, height), ) } fn interpolate(from: Point, to: Point, amount: f32) -> Point { Point { x: from.x + amount * (to.x - from.x), y: from.y + amount * (to.y - from.y), } }