diff --git a/src/ui/app.rs b/src/ui/app.rs index 3874643..eadb94c 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -183,6 +183,11 @@ impl App { && y < viewport_height - player::TRANSPORT_H } + /// checks whether a logical-coords point falls inside the right-aligned settings overlay panel. + pub fn point_in_settings(&self, x: f32, _y: f32, viewport_width: f32) -> bool { + self.show_settings && x >= viewport_width - player::SETTINGS_W && x <= viewport_width + } + /// scans a folder, replaces the library, queues art, and starts decoding the first track. fn apply_picked_folder(&mut self, folder: PathBuf) { #[cfg(all(target_os = "ios", debug_assertions))] diff --git a/src/ui/player.rs b/src/ui/player.rs index f2942c6..64603f9 100644 --- a/src/ui/player.rs +++ b/src/ui/player.rs @@ -386,7 +386,7 @@ fn params_from(s: &super::app::Settings) -> VizParams { } } -const SETTINGS_W: f32 = 340.0; +pub const SETTINGS_W: f32 = 340.0; /// right-aligned settings panel built from grouped slider and toggle rows. fn settings_overlay(app: &App) -> Element<'_, Message, Theme, iced_wgpu::Renderer> { @@ -530,23 +530,26 @@ fn slider_row<'a, F>( where F: 'a + Fn(f32) -> Message, { - let label_w = 96.0; - let value_w = 56.0; - row![ - container(text(label).size(12).color(palette::text_dim())) - .width(Length::Fixed(label_w)), - slider(range, value, on_change).step(step).width(Length::Fill), - container( - text(value_text) - .size(12) - .color(palette::text()) - .align_x(iced_wgpu::core::alignment::Horizontal::Right) - ) - .width(Length::Fixed(value_w)) - .align_right(Length::Fixed(value_w)), - ] - .spacing(10) - .align_y(iced_wgpu::core::Alignment::Center) + let label_w = 110.0; + let value_w = 60.0; + container( + row![ + container(text(label).size(13).color(palette::text_dim())) + .width(Length::Fixed(label_w)), + slider(range, value, on_change).step(step).width(Length::Fill).height(28.0), + container( + text(value_text) + .size(13) + .color(palette::text()) + .align_x(iced_wgpu::core::alignment::Horizontal::Right) + ) + .width(Length::Fixed(value_w)) + .align_right(Length::Fixed(value_w)), + ] + .spacing(12) + .align_y(iced_wgpu::core::Alignment::Center) + ) + .height(Length::Fixed(44.0)) .into() } @@ -584,13 +587,16 @@ fn toggle_row<'a, F>( where F: 'a + Fn(bool) -> Message, { - row![ - container(text(label).size(12).color(palette::text_dim())) - .width(Length::Fixed(96.0)), - checkbox(value).on_toggle(on_change).size(16), - ] - .spacing(10) - .align_y(iced_wgpu::core::Alignment::Center) + container( + row![ + container(text(label).size(13).color(palette::text_dim())) + .width(Length::Fixed(110.0)), + checkbox(value).on_toggle(on_change).size(26), + ] + .spacing(12) + .align_y(iced_wgpu::core::Alignment::Center) + ) + .height(Length::Fixed(40.0)) .into() } diff --git a/src/viewport.rs b/src/viewport.rs index fb38778..d787888 100644 --- a/src/viewport.rs +++ b/src/viewport.rs @@ -42,9 +42,21 @@ pub struct ViewportHandle { /// marks an active touch originating over the sidebar, routing vertical drags to wheel scrolls. touch_in_sidebar: bool, + + /// classification of an active touch over the settings panel: pending until SLOP, then tap/drag/scroll. + settings_touch: SettingsTouch, pub state: App, } +/// classifies an in-flight settings-panel touch once its dominant axis is known. +#[derive(Copy, Clone, PartialEq, Eq)] +enum SettingsTouch { + None, + Pending, + Drag, + Scroll, +} + /// stub clipboard handed to iced, returning empty on reads and dropping writes. struct NullClipboard; impl clipboard::Clipboard for NullClipboard { @@ -153,11 +165,10 @@ impl ViewportHandle { self.needs_redraw = true; } - /// folds an iOS touch into mouse-style events, treating sidebar drags as wheel scrolls. + /// folds an iOS touch into mouse-style events, treating sidebar/settings vertical drags as wheel scrolls. pub fn push_touch(&mut self, x: f32, y: f32, pressed: bool, moved: bool) { const TOUCH_TAP_SLOP: f32 = 10.0; if !pressed && !moved { - if self.touch_in_sidebar { if let Some((sx, sy)) = self.touch_start.take() { if self.touch_drift <= TOUCH_TAP_SLOP { @@ -166,39 +177,93 @@ impl ViewportHandle { } } } else { - self.push_mouse_button(x, y, 0, false); + match self.settings_touch { + SettingsTouch::None => { + self.push_mouse_button(x, y, 0, false); + } + SettingsTouch::Pending => { + if let Some((sx, sy)) = self.touch_start { + self.push_mouse_button(sx, sy, 0, true); + self.push_mouse_button(sx, sy, 0, false); + } + } + SettingsTouch::Drag => { + self.push_mouse_button(x, y, 0, false); + } + SettingsTouch::Scroll => {} + } } self.last_touch = None; + self.touch_start = None; self.touch_drift = 0.0; self.touch_in_sidebar = false; + self.settings_touch = SettingsTouch::None; return; } if pressed && !moved { - - let h = self.viewport.logical_size().height; + let logical = self.viewport.logical_size(); + let h = logical.height; + let w = logical.width; self.touch_in_sidebar = self.state.point_in_sidebar(x, y, h); + let in_settings = self.state.point_in_settings(x, y, w); self.touch_start = Some((x, y)); self.touch_drift = 0.0; self.last_touch = Some((x, y)); if self.touch_in_sidebar { self.push_mouse_move(x, y); + self.settings_touch = SettingsTouch::None; + } else if in_settings { + self.settings_touch = SettingsTouch::Pending; + self.push_mouse_move(x, y); } else { + self.settings_touch = SettingsTouch::None; self.push_mouse_button(x, y, 0, true); } return; } - self.push_mouse_move(x, y); if let Some((px, py)) = self.last_touch { let dx = x - px; let dy = y - py; self.touch_drift += (dx * dx + dy * dy).sqrt(); - if self.touch_in_sidebar && dy.abs() > 0.0 { - let p = Point::new(x, y); - self.events.push(Event::Mouse(mouse::Event::WheelScrolled { - delta: mouse::ScrollDelta::Pixels { x: 0.0, y: dy }, - })); - self.cursor = mouse::Cursor::Available(p); + + if self.settings_touch == SettingsTouch::Pending && self.touch_drift > TOUCH_TAP_SLOP { + if let Some((sx, sy)) = self.touch_start { + let total_dx = (x - sx).abs(); + let total_dy = (y - sy).abs(); + if total_dy > total_dx { + self.settings_touch = SettingsTouch::Scroll; + } else { + self.settings_touch = SettingsTouch::Drag; + self.push_mouse_button(sx, sy, 0, true); + } + } + } + + match self.settings_touch { + SettingsTouch::Scroll => { + if dy.abs() > 0.0 { + let p = Point::new(x, y); + self.events.push(Event::Mouse(mouse::Event::WheelScrolled { + delta: mouse::ScrollDelta::Pixels { x: 0.0, y: dy }, + })); + self.cursor = mouse::Cursor::Available(p); + } + } + SettingsTouch::Drag => { + self.push_mouse_move(x, y); + } + SettingsTouch::Pending => {} + SettingsTouch::None => { + self.push_mouse_move(x, y); + if self.touch_in_sidebar && dy.abs() > 0.0 { + let p = Point::new(x, y); + self.events.push(Event::Mouse(mouse::Event::WheelScrolled { + delta: mouse::ScrollDelta::Pixels { x: 0.0, y: dy }, + })); + self.cursor = mouse::Cursor::Available(p); + } + } } } self.last_touch = Some((x, y)); @@ -425,6 +490,7 @@ fn finalise( touch_start: None, touch_drift: 0.0, touch_in_sidebar: false, + settings_touch: SettingsTouch::None, state, }) }