Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save bq-wrongway/7131ff9334634f39a26bab76bb521523 to your computer and use it in GitHub Desktop.

Select an option

Save bq-wrongway/7131ff9334634f39a26bab76bb521523 to your computer and use it in GitHub Desktop.
working_wave_widget
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