Created
July 2, 2025 11:17
-
-
Save bq-wrongway/7131ff9334634f39a26bab76bb521523 to your computer and use it in GitHub Desktop.
working_wave_widget
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use iced::{ | |
| widget::{button, canvas::{self, Canvas, Frame, Path, Program }, column, row}, Element, Length, Point, Renderer, Settings, Size, Subscription, Task, Theme | |
| }; | |
| use std::time::{Duration, Instant}; | |
| use std::f32::consts::PI; | |
| fn main() -> iced::Result { | |
| iced::application( | |
| SineWaveApp::new, | |
| SineWaveApp::update, | |
| SineWaveApp::view, | |
| ) | |
| .subscription(SineWaveApp::subscription) | |
| .title("iced • Now Playing") | |
| .window_size([400.0, 200.0]) | |
| .theme(|_| iced::Theme::GruvboxDark) | |
| .centered().run() | |
| } | |
| #[derive(Debug, Clone, Copy)] | |
| enum Message { | |
| Toggle, | |
| Tick(Instant), | |
| } | |
| struct SineWaveApp { | |
| playing: bool, | |
| phase: f32, | |
| last_tick: Instant, | |
| } | |
| impl SineWaveApp { | |
| fn new() -> (Self, Task<Message>) { | |
| ( | |
| SineWaveApp { | |
| playing: false, | |
| phase: 0.0, | |
| last_tick: Instant::now(), | |
| }, | |
| Task::none(), | |
| ) | |
| } | |
| fn title(&self) -> String { | |
| String::from("Iced Sinewave Widget [master]") | |
| } | |
| fn update(&mut self, message: Message) -> Task<Message> { | |
| match message { | |
| Message::Toggle => { | |
| self.playing = !self.playing; | |
| } | |
| Message::Tick(now) => { | |
| if self.playing { | |
| let delta = now.duration_since(self.last_tick).as_secs_f32(); | |
| self.phase = (self.phase + delta * 2.0 * PI * 0.6) % (2.0 * PI); // 0.5 Hz | |
| } | |
| self.last_tick = now; | |
| } | |
| } | |
| Task::none() | |
| } | |
| fn view(&self) -> Element<Message> { | |
| let sine_widget = Canvas::new(SineWaveWidget { phase: self.phase }) | |
| .width(Length::Fill) | |
| .height(Length::FillPortion(3)); | |
| let btn = button(if self.playing { "Pause" } else { "Play" }) | |
| .on_press(Message::Toggle); | |
| column![ | |
| sine_widget, | |
| row![btn].spacing(20), | |
| ] | |
| .padding(20) | |
| .spacing(20) | |
| .into() | |
| } | |
| fn subscription(&self) -> Subscription<Message> { | |
| iced::time::every(Duration::from_millis(16)) | |
| .map(Message::Tick) | |
| } | |
| } | |
| struct SineWaveWidget { | |
| phase: f32, | |
| } | |
| impl<Message> Program<Message> for SineWaveWidget { | |
| type State = (); | |
| fn draw( | |
| &self, | |
| _state: &Self::State, | |
| renderer: &Renderer, | |
| theme: &Theme, | |
| bounds: iced::Rectangle, | |
| _cursor: iced::mouse::Cursor, | |
| ) -> Vec<canvas::Geometry> { | |
| let mut frame = Frame::new(renderer,bounds.size()); | |
| let width = bounds.width; | |
| let height = bounds.height; | |
| let loader_width = width * 0.8; | |
| let loader_height = height * 0.6; | |
| let x_start = (width - loader_width) / 2.0; | |
| let y_base = height / 2.0; | |
| let bar_count = 7; | |
| let bar_width = loader_width / (bar_count as f32 * 2.0); | |
| let bar_spacing = loader_width / (bar_count as f32); | |
| for i in 0..bar_count { | |
| let x = x_start + i as f32 * bar_spacing; | |
| // Animate each bar with a phase offset | |
| let offset = i as f32 * 0.4; | |
| let wave = ((self.phase + offset).sin() + 1.0) / 2.0; | |
| let bar_h = loader_height * (0.3 + 0.7 * wave); | |
| let y = y_base - bar_h / 2.0; | |
| let rect = iced::Rectangle { | |
| x, | |
| y, | |
| width: bar_width, | |
| height: bar_h, | |
| }; | |
| let rounded_rect_path = Path::new(|p| { | |
| p.rounded_rectangle( | |
| Point::new(x, y / 2.0), | |
| rect.size(), | |
| 15.into(), | |
| ); | |
| }); | |
| let palette = theme.extended_palette(); | |
| let custom_color = palette.success.base.color; | |
| frame.fill( | |
| &rounded_rect_path,custom_color | |
| ); | |
| // // Optional: round the ends | |
| // frame.stroke_rectangle( | |
| // rect.position(), | |
| // rect.size(), | |
| // canvas::Stroke { | |
| // width: 1.5, | |
| // // color: Color::from_rgb(0.1, 0.4, 0.7), | |
| // ..Default::default() | |
| // }, | |
| // ); | |
| } | |
| vec![frame.into_geometry()] | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment