diff options
author | 2024-10-22 00:45:36 +0200 | |
---|---|---|
committer | 2024-11-05 23:52:56 +0100 | |
commit | 3ba7c71e3ffb651fde753bcf63bb604c16d4bcc2 (patch) | |
tree | 2978ac7b4ab6c651f58d830727ec24792884db5a | |
parent | 97bcca04002d9d7c4812e178d30fb12358fad72c (diff) | |
download | iced-3ba7c71e3ffb651fde753bcf63bb604c16d4bcc2.tar.gz iced-3ba7c71e3ffb651fde753bcf63bb604c16d4bcc2.tar.bz2 iced-3ba7c71e3ffb651fde753bcf63bb604c16d4bcc2.zip |
Implement `reactive-rendering` for `slider`
-rw-r--r-- | widget/src/slider.rs | 290 | ||||
-rw-r--r-- | winit/src/program.rs | 2 |
2 files changed, 160 insertions, 132 deletions
diff --git a/widget/src/slider.rs b/widget/src/slider.rs index 31aa0e0c..25f0d85f 100644 --- a/widget/src/slider.rs +++ b/widget/src/slider.rs @@ -37,6 +37,7 @@ use crate::core::mouse; use crate::core::renderer; use crate::core::touch; use crate::core::widget::tree::{self, Tree}; +use crate::core::window; use crate::core::{ self, Background, Clipboard, Color, Element, Layout, Length, Pixels, Point, Rectangle, Shell, Size, Theme, Widget, @@ -95,6 +96,7 @@ where width: Length, height: f32, class: Theme::Class<'a>, + status: Option<Status>, } impl<'a, T, Message, Theme> Slider<'a, T, Message, Theme> @@ -141,6 +143,7 @@ where width: Length::Fill, height: Self::DEFAULT_HEIGHT, class: Theme::default(), + status: None, } } @@ -253,185 +256,208 @@ where ) -> event::Status { let state = tree.state.downcast_mut::<State>(); - let is_dragging = state.is_dragging; - let current_value = self.value; + let mut update = || { + let current_value = self.value; - let locate = |cursor_position: Point| -> Option<T> { - let bounds = layout.bounds(); - let new_value = if cursor_position.x <= bounds.x { - Some(*self.range.start()) - } else if cursor_position.x >= bounds.x + bounds.width { - Some(*self.range.end()) - } else { - let step = if state.keyboard_modifiers.shift() { - self.shift_step.unwrap_or(self.step) + let locate = |cursor_position: Point| -> Option<T> { + let bounds = layout.bounds(); + + let new_value = if cursor_position.x <= bounds.x { + Some(*self.range.start()) + } else if cursor_position.x >= bounds.x + bounds.width { + Some(*self.range.end()) } else { - self.step - } - .into(); + let step = if state.keyboard_modifiers.shift() { + self.shift_step.unwrap_or(self.step) + } else { + self.step + } + .into(); - let start = (*self.range.start()).into(); - let end = (*self.range.end()).into(); + let start = (*self.range.start()).into(); + let end = (*self.range.end()).into(); - let percent = f64::from(cursor_position.x - bounds.x) - / f64::from(bounds.width); + let percent = f64::from(cursor_position.x - bounds.x) + / f64::from(bounds.width); - let steps = (percent * (end - start) / step).round(); - let value = steps * step + start; + let steps = (percent * (end - start) / step).round(); + let value = steps * step + start; - T::from_f64(value.min(end)) + T::from_f64(value.min(end)) + }; + + new_value }; - new_value - }; + let increment = |value: T| -> Option<T> { + let step = if state.keyboard_modifiers.shift() { + self.shift_step.unwrap_or(self.step) + } else { + self.step + } + .into(); - let increment = |value: T| -> Option<T> { - let step = if state.keyboard_modifiers.shift() { - self.shift_step.unwrap_or(self.step) - } else { - self.step - } - .into(); + let steps = (value.into() / step).round(); + let new_value = step * (steps + 1.0); - let steps = (value.into() / step).round(); - let new_value = step * (steps + 1.0); + if new_value > (*self.range.end()).into() { + return Some(*self.range.end()); + } - if new_value > (*self.range.end()).into() { - return Some(*self.range.end()); - } + T::from_f64(new_value) + }; - T::from_f64(new_value) - }; + let decrement = |value: T| -> Option<T> { + let step = if state.keyboard_modifiers.shift() { + self.shift_step.unwrap_or(self.step) + } else { + self.step + } + .into(); - let decrement = |value: T| -> Option<T> { - let step = if state.keyboard_modifiers.shift() { - self.shift_step.unwrap_or(self.step) - } else { - self.step - } - .into(); + let steps = (value.into() / step).round(); + let new_value = step * (steps - 1.0); - let steps = (value.into() / step).round(); - let new_value = step * (steps - 1.0); + if new_value < (*self.range.start()).into() { + return Some(*self.range.start()); + } - if new_value < (*self.range.start()).into() { - return Some(*self.range.start()); - } + T::from_f64(new_value) + }; - T::from_f64(new_value) - }; + let change = |new_value: T| { + if (self.value.into() - new_value.into()).abs() > f64::EPSILON { + shell.publish((self.on_change)(new_value)); - let change = |new_value: T| { - if (self.value.into() - new_value.into()).abs() > f64::EPSILON { - shell.publish((self.on_change)(new_value)); + self.value = new_value; + } + }; - self.value = new_value; - } - }; + match &event { + Event::Mouse(mouse::Event::ButtonPressed( + mouse::Button::Left, + )) + | Event::Touch(touch::Event::FingerPressed { .. }) => { + if let Some(cursor_position) = + cursor.position_over(layout.bounds()) + { + if state.keyboard_modifiers.command() { + let _ = self.default.map(change); + state.is_dragging = false; + } else { + let _ = locate(cursor_position).map(change); + state.is_dragging = true; + } - match event { - Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) - | Event::Touch(touch::Event::FingerPressed { .. }) => { - if let Some(cursor_position) = - cursor.position_over(layout.bounds()) - { - if state.keyboard_modifiers.command() { - let _ = self.default.map(change); - state.is_dragging = false; - } else { - let _ = locate(cursor_position).map(change); - state.is_dragging = true; + return event::Status::Captured; } - - return event::Status::Captured; } - } - Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) - | Event::Touch(touch::Event::FingerLifted { .. }) - | Event::Touch(touch::Event::FingerLost { .. }) => { - if is_dragging { - if let Some(on_release) = self.on_release.clone() { - shell.publish(on_release); - } - state.is_dragging = false; + Event::Mouse(mouse::Event::ButtonReleased( + mouse::Button::Left, + )) + | Event::Touch(touch::Event::FingerLifted { .. }) + | Event::Touch(touch::Event::FingerLost { .. }) => { + if state.is_dragging { + if let Some(on_release) = self.on_release.clone() { + shell.publish(on_release); + } + state.is_dragging = false; - return event::Status::Captured; + return event::Status::Captured; + } } - } - Event::Mouse(mouse::Event::CursorMoved { .. }) - | Event::Touch(touch::Event::FingerMoved { .. }) => { - if is_dragging { - let _ = cursor.position().and_then(locate).map(change); + Event::Mouse(mouse::Event::CursorMoved { .. }) + | Event::Touch(touch::Event::FingerMoved { .. }) => { + if state.is_dragging { + let _ = cursor.position().and_then(locate).map(change); - return event::Status::Captured; - } - } - Event::Mouse(mouse::Event::WheelScrolled { delta }) - if state.keyboard_modifiers.control() => - { - if cursor.is_over(layout.bounds()) { - let delta = match delta { - mouse::ScrollDelta::Lines { x: _, y } => y, - mouse::ScrollDelta::Pixels { x: _, y } => y, - }; - - if delta < 0.0 { - let _ = decrement(current_value).map(change); - } else { - let _ = increment(current_value).map(change); + return event::Status::Captured; } - - return event::Status::Captured; } - } - Event::Keyboard(keyboard::Event::KeyPressed { key, .. }) => { - if cursor.is_over(layout.bounds()) { - match key { - Key::Named(key::Named::ArrowUp) => { - let _ = increment(current_value).map(change); - } - Key::Named(key::Named::ArrowDown) => { + Event::Mouse(mouse::Event::WheelScrolled { delta }) + if state.keyboard_modifiers.control() => + { + if cursor.is_over(layout.bounds()) { + let delta = match delta { + mouse::ScrollDelta::Lines { x: _, y } => y, + mouse::ScrollDelta::Pixels { x: _, y } => y, + }; + + if *delta < 0.0 { let _ = decrement(current_value).map(change); + } else { + let _ = increment(current_value).map(change); } - _ => (), + + return event::Status::Captured; } + } + Event::Keyboard(keyboard::Event::KeyPressed { + key, .. + }) => { + if cursor.is_over(layout.bounds()) { + match key { + Key::Named(key::Named::ArrowUp) => { + let _ = increment(current_value).map(change); + } + Key::Named(key::Named::ArrowDown) => { + let _ = decrement(current_value).map(change); + } + _ => (), + } - return event::Status::Captured; + return event::Status::Captured; + } } + Event::Keyboard(keyboard::Event::ModifiersChanged( + modifiers, + )) => { + state.keyboard_modifiers = *modifiers; + } + _ => {} } - Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => { - state.keyboard_modifiers = modifiers; + + event::Status::Ignored + }; + + let update_status = update(); + + let current_status = if state.is_dragging { + Status::Dragged + } else if cursor.is_over(layout.bounds()) { + Status::Hovered + } else { + Status::Active + }; + + if let Event::Window(window::Event::RedrawRequested(_now)) = event { + self.status = Some(current_status); + } else { + match self.status { + Some(status) if status != current_status => { + shell.request_redraw(window::RedrawRequest::NextFrame); + } + _ => {} } - _ => {} } - event::Status::Ignored + update_status } fn draw( &self, - tree: &Tree, + _tree: &Tree, renderer: &mut Renderer, theme: &Theme, _style: &renderer::Style, layout: Layout<'_>, - cursor: mouse::Cursor, + _cursor: mouse::Cursor, _viewport: &Rectangle, ) { - let state = tree.state.downcast_ref::<State>(); let bounds = layout.bounds(); - let is_mouse_over = cursor.is_over(bounds); - let style = theme.style( - &self.class, - if state.is_dragging { - Status::Dragged - } else if is_mouse_over { - Status::Hovered - } else { - Status::Active - }, - ); + let style = + theme.style(&self.class, self.status.unwrap_or(Status::Active)); let (handle_width, handle_height, handle_border_radius) = match style.handle.shape { diff --git a/winit/src/program.rs b/winit/src/program.rs index f15e5be5..579038af 100644 --- a/winit/src/program.rs +++ b/winit/src/program.rs @@ -1161,6 +1161,8 @@ async fn run_instance<P, C>( } if !redraw_queue.is_empty() { + // The queue should be fairly short, so we can + // simply sort all of the time. redraw_queue.sort_by( |(target_a, _), (target_b, _)| { target_a.cmp(target_b).reverse() |