Implement reactive-rendering for slider

This commit is contained in:
Héctor Ramón Jiménez 2024-10-22 00:45:36 +02:00
parent 97bcca0400
commit 3ba7c71e3f
No known key found for this signature in database
GPG key ID: 4C07CEC81AFA161F
2 changed files with 162 additions and 134 deletions

View file

@ -37,6 +37,7 @@ use crate::core::mouse;
use crate::core::renderer; use crate::core::renderer;
use crate::core::touch; use crate::core::touch;
use crate::core::widget::tree::{self, Tree}; use crate::core::widget::tree::{self, Tree};
use crate::core::window;
use crate::core::{ use crate::core::{
self, Background, Clipboard, Color, Element, Layout, Length, Pixels, Point, self, Background, Clipboard, Color, Element, Layout, Length, Pixels, Point,
Rectangle, Shell, Size, Theme, Widget, Rectangle, Shell, Size, Theme, Widget,
@ -95,6 +96,7 @@ where
width: Length, width: Length,
height: f32, height: f32,
class: Theme::Class<'a>, class: Theme::Class<'a>,
status: Option<Status>,
} }
impl<'a, T, Message, Theme> Slider<'a, T, Message, Theme> impl<'a, T, Message, Theme> Slider<'a, T, Message, Theme>
@ -141,6 +143,7 @@ where
width: Length::Fill, width: Length::Fill,
height: Self::DEFAULT_HEIGHT, height: Self::DEFAULT_HEIGHT,
class: Theme::default(), class: Theme::default(),
status: None,
} }
} }
@ -253,11 +256,12 @@ where
) -> event::Status { ) -> event::Status {
let state = tree.state.downcast_mut::<State>(); let state = tree.state.downcast_mut::<State>();
let is_dragging = state.is_dragging; let mut update = || {
let current_value = self.value; let current_value = self.value;
let locate = |cursor_position: Point| -> Option<T> { let locate = |cursor_position: Point| -> Option<T> {
let bounds = layout.bounds(); let bounds = layout.bounds();
let new_value = if cursor_position.x <= bounds.x { let new_value = if cursor_position.x <= bounds.x {
Some(*self.range.start()) Some(*self.range.start())
} else if cursor_position.x >= bounds.x + bounds.width { } else if cursor_position.x >= bounds.x + bounds.width {
@ -329,8 +333,10 @@ where
} }
}; };
match event { match &event {
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) Event::Mouse(mouse::Event::ButtonPressed(
mouse::Button::Left,
))
| Event::Touch(touch::Event::FingerPressed { .. }) => { | Event::Touch(touch::Event::FingerPressed { .. }) => {
if let Some(cursor_position) = if let Some(cursor_position) =
cursor.position_over(layout.bounds()) cursor.position_over(layout.bounds())
@ -346,10 +352,12 @@ where
return event::Status::Captured; return event::Status::Captured;
} }
} }
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) Event::Mouse(mouse::Event::ButtonReleased(
mouse::Button::Left,
))
| Event::Touch(touch::Event::FingerLifted { .. }) | Event::Touch(touch::Event::FingerLifted { .. })
| Event::Touch(touch::Event::FingerLost { .. }) => { | Event::Touch(touch::Event::FingerLost { .. }) => {
if is_dragging { if state.is_dragging {
if let Some(on_release) = self.on_release.clone() { if let Some(on_release) = self.on_release.clone() {
shell.publish(on_release); shell.publish(on_release);
} }
@ -360,7 +368,7 @@ where
} }
Event::Mouse(mouse::Event::CursorMoved { .. }) Event::Mouse(mouse::Event::CursorMoved { .. })
| Event::Touch(touch::Event::FingerMoved { .. }) => { | Event::Touch(touch::Event::FingerMoved { .. }) => {
if is_dragging { if state.is_dragging {
let _ = cursor.position().and_then(locate).map(change); let _ = cursor.position().and_then(locate).map(change);
return event::Status::Captured; return event::Status::Captured;
@ -375,7 +383,7 @@ where
mouse::ScrollDelta::Pixels { x: _, y } => y, mouse::ScrollDelta::Pixels { x: _, y } => y,
}; };
if delta < 0.0 { if *delta < 0.0 {
let _ = decrement(current_value).map(change); let _ = decrement(current_value).map(change);
} else { } else {
let _ = increment(current_value).map(change); let _ = increment(current_value).map(change);
@ -384,7 +392,9 @@ where
return event::Status::Captured; return event::Status::Captured;
} }
} }
Event::Keyboard(keyboard::Event::KeyPressed { key, .. }) => { Event::Keyboard(keyboard::Event::KeyPressed {
key, ..
}) => {
if cursor.is_over(layout.bounds()) { if cursor.is_over(layout.bounds()) {
match key { match key {
Key::Named(key::Named::ArrowUp) => { Key::Named(key::Named::ArrowUp) => {
@ -399,39 +409,55 @@ where
return event::Status::Captured; return event::Status::Captured;
} }
} }
Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => { Event::Keyboard(keyboard::Event::ModifiersChanged(
state.keyboard_modifiers = modifiers; modifiers,
)) => {
state.keyboard_modifiers = *modifiers;
} }
_ => {} _ => {}
} }
event::Status::Ignored 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);
}
_ => {}
}
}
update_status
} }
fn draw( fn draw(
&self, &self,
tree: &Tree, _tree: &Tree,
renderer: &mut Renderer, renderer: &mut Renderer,
theme: &Theme, theme: &Theme,
_style: &renderer::Style, _style: &renderer::Style,
layout: Layout<'_>, layout: Layout<'_>,
cursor: mouse::Cursor, _cursor: mouse::Cursor,
_viewport: &Rectangle, _viewport: &Rectangle,
) { ) {
let state = tree.state.downcast_ref::<State>();
let bounds = layout.bounds(); let bounds = layout.bounds();
let is_mouse_over = cursor.is_over(bounds);
let style = theme.style( let style =
&self.class, theme.style(&self.class, self.status.unwrap_or(Status::Active));
if state.is_dragging {
Status::Dragged
} else if is_mouse_over {
Status::Hovered
} else {
Status::Active
},
);
let (handle_width, handle_height, handle_border_radius) = let (handle_width, handle_height, handle_border_radius) =
match style.handle.shape { match style.handle.shape {

View file

@ -1161,6 +1161,8 @@ async fn run_instance<P, C>(
} }
if !redraw_queue.is_empty() { if !redraw_queue.is_empty() {
// The queue should be fairly short, so we can
// simply sort all of the time.
redraw_queue.sort_by( redraw_queue.sort_by(
|(target_a, _), (target_b, _)| { |(target_a, _), (target_b, _)| {
target_a.cmp(target_b).reverse() target_a.cmp(target_b).reverse()