zoom on time line

This commit is contained in:
2025-07-19 13:34:15 +02:00
parent ad6d09b8a5
commit d841c9fdb4
2 changed files with 81 additions and 19 deletions

View File

@@ -17,12 +17,12 @@ mod gui;
use gui::{load_file_view, music_view};
use iced::Font;
use iced::Theme;
use iced::{
Color, Event, Task,
event::{self, Status},
keyboard::{Key, key::Named},
};
use iced::Theme;
use std::time::Instant;
@@ -190,7 +190,6 @@ impl MyApp {
}
Message::ChangeDelta(f) => {
self.already_save = false;
self.current_delta = f;
self.music.fix_teta(self.current_delta);
// update the red dot on canvas

View File

@@ -5,11 +5,14 @@ use serde::{Deserialize, Serialize};
use kira::{AudioManager, sound::static_sound::StaticSoundData};
use iced::Vector;
use iced::event::Status;
use iced::mouse::Cursor;
use iced::widget::canvas::{Event, Geometry};
use iced::{Size, mouse};
use iced::{
Size,
mouse::{self, ScrollDelta},
};
use iced::{Vector, keyboard};
use iced::widget::canvas;
use iced::widget::canvas::Stroke;
@@ -175,13 +178,21 @@ impl Music {
}
}
}
#[derive(Default, Debug)]
pub struct StateMusic {
mouse_left: bool,
ctrl: bool,
zoom: f32,
offset: f32,
}
impl canvas::Program<Message> for Music {
// No internal state
type State = bool;
type State = StateMusic;
fn draw(
&self,
_state: &Self::State,
state: &Self::State,
renderer: &Renderer,
_theme: &Theme,
bounds: Rectangle,
@@ -190,22 +201,26 @@ impl canvas::Program<Message> for Music {
let mut geo_small_frame: Vec<Geometry> = vec![];
let mut geo_cursor: Vec<Geometry> = vec![];
let frame = canvas::Frame::new(renderer, bounds.size());
let global_width = bounds.width * state.zoom;
let mut toggle_color = true;
let padding = 8.;
let w = bounds.width - (padding * 2.);
let w = global_width - (padding * 2.);
for (delta, polyframe) in &self.poly_frame {
let x = delta / self.length * w + 8.;
let x = delta / self.length * w + 8. - state.offset;
let mut back_frame = canvas::Frame::new(
renderer,
Size {
width: bounds.width,
width: global_width.clamp(0.0, bounds.width),
height: bounds.height,
},
);
back_frame.fill_rectangle(
iced::Point { x: x, y: 0.0 },
frame.size(),
Size {
width: global_width,
height: bounds.height,
},
if toggle_color {
Color::from_rgb8(27, 60, 83)
} else {
@@ -217,7 +232,7 @@ impl canvas::Program<Message> for Music {
let mut small_frame = canvas::Frame::new(
renderer,
Size {
width: bounds.width,
width: global_width.clamp(0.0, bounds.width),
height: bounds.height,
},
);
@@ -236,7 +251,7 @@ impl canvas::Program<Message> for Music {
geo_small_frame.push(small_frame.into_geometry());
}
let x = self.current_delta / self.length * w + 8.;
let x = self.current_delta / self.length * w + 8. - state.offset;
let mut frame_cursor = canvas::Frame::new(renderer, bounds.size());
frame_cursor.stroke_rectangle(
iced::Point::new(x, 0.),
@@ -251,8 +266,14 @@ impl canvas::Program<Message> for Music {
},
);
frame_cursor.stroke_rectangle(
iced::Point { x: 0.0, y: 0.0 },
frame.size(),
iced::Point {
x: -state.offset,
y: 0.0,
},
iced::Size {
width: global_width,
height: bounds.height,
},
Stroke {
width: 16.0,
style: Style::Solid(Color::from_rgb8(207, 74, 28)),
@@ -276,12 +297,21 @@ impl canvas::Program<Message> for Music {
cursor: Cursor,
) -> (Status, Option<Message>) {
//eprintln!("event = {:?}", event);
if let Event::Keyboard(keyboard_event) = &event {
match keyboard_event {
keyboard::Event::ModifiersChanged(m) => {
state.ctrl = m.control();
}
_ => (),
}
}
if let Event::Mouse(mouse_event) = event {
match mouse_event {
mouse::Event::ButtonPressed(mouse::Button::Left) => {
*state = true;
state.mouse_left = true;
if let Some(position) = cursor.position_in(bounds) {
let pos_x = (position.x - 8.0) / (bounds.width - 16.);
let pos_x =
(position.x + state.offset - 8.0) / (bounds.width * state.zoom - 16.);
let delta = (pos_x * self.length).clamp(0., self.length);
return (
Status::Captured,
@@ -289,19 +319,52 @@ impl canvas::Program<Message> for Music {
);
}
}
mouse::Event::ButtonReleased(mouse::Button::Left) => *state = false,
mouse::Event::ButtonReleased(mouse::Button::Left) => state.mouse_left = false,
mouse::Event::CursorMoved { position: _ } => {
if let Some(position) = cursor.position_in(bounds)
&& *state
&& state.mouse_left
{
let pos_x = (position.x - 8.0) / (bounds.width - 16.);
let pos_x =
(position.x + state.offset - 8.0) / (bounds.width * state.zoom - 16.);
let delta = (pos_x * self.length).clamp(0., self.length);
return (Status::Captured, Some(Message::ClickedOnTimeLine(delta)));
}
}
mouse::Event::WheelScrolled { delta: d } => {
if state.ctrl {
match d {
ScrollDelta::Lines { x: _, y } => {
let before = bounds.width * state.zoom;
state.zoom += y / 10.;
state.offset = state.offset * (bounds.width * state.zoom) / before;
}
ScrollDelta::Pixels { x: _, y } => {
let before = bounds.width * state.zoom;
state.zoom += y / 10.;
state.offset = state.offset * (bounds.width * state.zoom) / before;
}
}
} else {
match d {
ScrollDelta::Lines { x: _, y } => {
state.offset -= y * 32. * state.zoom;
}
ScrollDelta::Pixels { x: _, y } => {
state.offset -= y * 32. * state.zoom;
}
}
}
}
_ => {}
}
}
state.zoom = state.zoom.clamp(1.0, 10.);
if state.offset + bounds.width >= bounds.width * state.zoom {
state.offset = bounds.width * state.zoom - bounds.width
}
if state.offset <= 0. {
state.offset = 0.
}
(Status::Ignored, None)
}