Implement basic cursor availability
This commit is contained in:
parent
c15f1b5f65
commit
34451bff18
55 changed files with 731 additions and 886 deletions
|
|
@ -222,7 +222,7 @@ where
|
|||
tree: &mut Tree,
|
||||
event: Event,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
cursor: mouse::Cursor,
|
||||
renderer: &Renderer,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
|
|
@ -231,18 +231,18 @@ where
|
|||
tree.state.downcast_mut::<State>(),
|
||||
event,
|
||||
layout,
|
||||
cursor_position,
|
||||
cursor,
|
||||
clipboard,
|
||||
shell,
|
||||
&self.vertical,
|
||||
self.horizontal.as_ref(),
|
||||
&self.on_scroll,
|
||||
|event, layout, cursor_position, clipboard, shell| {
|
||||
|event, layout, cursor, clipboard, shell| {
|
||||
self.content.as_widget_mut().on_event(
|
||||
&mut tree.children[0],
|
||||
event,
|
||||
layout,
|
||||
cursor_position,
|
||||
cursor,
|
||||
renderer,
|
||||
clipboard,
|
||||
shell,
|
||||
|
|
@ -258,7 +258,7 @@ where
|
|||
theme: &Renderer::Theme,
|
||||
style: &renderer::Style,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
cursor: mouse::Cursor,
|
||||
_viewport: &Rectangle,
|
||||
) {
|
||||
draw(
|
||||
|
|
@ -266,18 +266,18 @@ where
|
|||
renderer,
|
||||
theme,
|
||||
layout,
|
||||
cursor_position,
|
||||
cursor,
|
||||
&self.vertical,
|
||||
self.horizontal.as_ref(),
|
||||
&self.style,
|
||||
|renderer, layout, cursor_position, viewport| {
|
||||
|renderer, layout, cursor, viewport| {
|
||||
self.content.as_widget().draw(
|
||||
&tree.children[0],
|
||||
renderer,
|
||||
theme,
|
||||
style,
|
||||
layout,
|
||||
cursor_position,
|
||||
cursor,
|
||||
viewport,
|
||||
)
|
||||
},
|
||||
|
|
@ -288,21 +288,21 @@ where
|
|||
&self,
|
||||
tree: &Tree,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
cursor: mouse::Cursor,
|
||||
_viewport: &Rectangle,
|
||||
renderer: &Renderer,
|
||||
) -> mouse::Interaction {
|
||||
mouse_interaction(
|
||||
tree.state.downcast_ref::<State>(),
|
||||
layout,
|
||||
cursor_position,
|
||||
cursor,
|
||||
&self.vertical,
|
||||
self.horizontal.as_ref(),
|
||||
|layout, cursor_position, viewport| {
|
||||
|layout, cursor, viewport| {
|
||||
self.content.as_widget().mouse_interaction(
|
||||
&tree.children[0],
|
||||
layout,
|
||||
cursor_position,
|
||||
cursor,
|
||||
viewport,
|
||||
renderer,
|
||||
)
|
||||
|
|
@ -428,7 +428,7 @@ pub fn update<Message>(
|
|||
state: &mut State,
|
||||
event: Event,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
cursor: mouse::Cursor,
|
||||
clipboard: &mut dyn Clipboard,
|
||||
shell: &mut Shell<'_, Message>,
|
||||
vertical: &Properties,
|
||||
|
|
@ -437,13 +437,13 @@ pub fn update<Message>(
|
|||
update_content: impl FnOnce(
|
||||
Event,
|
||||
Layout<'_>,
|
||||
Point,
|
||||
mouse::Cursor,
|
||||
&mut dyn Clipboard,
|
||||
&mut Shell<'_, Message>,
|
||||
) -> event::Status,
|
||||
) -> event::Status {
|
||||
let bounds = layout.bounds();
|
||||
let mouse_over_scrollable = bounds.contains(cursor_position);
|
||||
let cursor_over_scrollable = cursor.position_over(&bounds);
|
||||
|
||||
let content = layout.children().next().unwrap();
|
||||
let content_bounds = content.bounds();
|
||||
|
|
@ -452,28 +452,21 @@ pub fn update<Message>(
|
|||
Scrollbars::new(state, vertical, horizontal, bounds, content_bounds);
|
||||
|
||||
let (mouse_over_y_scrollbar, mouse_over_x_scrollbar) =
|
||||
scrollbars.is_mouse_over(cursor_position);
|
||||
scrollbars.is_mouse_over(cursor);
|
||||
|
||||
let event_status = {
|
||||
let cursor_position = if mouse_over_scrollable
|
||||
&& !(mouse_over_y_scrollbar || mouse_over_x_scrollbar)
|
||||
{
|
||||
cursor_position + state.offset(bounds, content_bounds)
|
||||
} else {
|
||||
// TODO: Make `cursor_position` an `Option<Point>` so we can encode
|
||||
// cursor availability.
|
||||
// This will probably happen naturally once we add multi-window
|
||||
// support.
|
||||
Point::new(-1.0, -1.0)
|
||||
let cursor = match cursor_over_scrollable {
|
||||
Some(cursor_position)
|
||||
if !(mouse_over_x_scrollbar || mouse_over_y_scrollbar) =>
|
||||
{
|
||||
mouse::Cursor::Available(
|
||||
cursor_position + state.offset(bounds, content_bounds),
|
||||
)
|
||||
}
|
||||
_ => mouse::Cursor::Unavailable,
|
||||
};
|
||||
|
||||
update_content(
|
||||
event.clone(),
|
||||
content,
|
||||
cursor_position,
|
||||
clipboard,
|
||||
shell,
|
||||
)
|
||||
update_content(event.clone(), content, cursor, clipboard, shell)
|
||||
};
|
||||
|
||||
if let event::Status::Captured = event_status {
|
||||
|
|
@ -487,76 +480,71 @@ pub fn update<Message>(
|
|||
return event::Status::Ignored;
|
||||
}
|
||||
|
||||
if mouse_over_scrollable {
|
||||
match event {
|
||||
Event::Mouse(mouse::Event::WheelScrolled { delta }) => {
|
||||
let delta = match delta {
|
||||
mouse::ScrollDelta::Lines { x, y } => {
|
||||
// TODO: Configurable speed/friction (?)
|
||||
let movement = if state.keyboard_modifiers.shift() {
|
||||
Vector::new(y, x)
|
||||
} else {
|
||||
Vector::new(x, y)
|
||||
};
|
||||
let Some(cursor_position) = cursor_over_scrollable else {
|
||||
return event::Status::Ignored
|
||||
};
|
||||
|
||||
movement * 60.0
|
||||
}
|
||||
mouse::ScrollDelta::Pixels { x, y } => Vector::new(x, y),
|
||||
};
|
||||
match event {
|
||||
Event::Mouse(mouse::Event::WheelScrolled { delta }) => {
|
||||
let delta = match delta {
|
||||
mouse::ScrollDelta::Lines { x, y } => {
|
||||
// TODO: Configurable speed/friction (?)
|
||||
let movement = if state.keyboard_modifiers.shift() {
|
||||
Vector::new(y, x)
|
||||
} else {
|
||||
Vector::new(x, y)
|
||||
};
|
||||
|
||||
state.scroll(delta, bounds, content_bounds);
|
||||
movement * 60.0
|
||||
}
|
||||
mouse::ScrollDelta::Pixels { x, y } => Vector::new(x, y),
|
||||
};
|
||||
|
||||
notify_on_scroll(
|
||||
state,
|
||||
on_scroll,
|
||||
bounds,
|
||||
content_bounds,
|
||||
shell,
|
||||
);
|
||||
state.scroll(delta, bounds, content_bounds);
|
||||
|
||||
notify_on_scroll(state, on_scroll, bounds, content_bounds, shell);
|
||||
|
||||
return event::Status::Captured;
|
||||
}
|
||||
Event::Touch(event)
|
||||
if state.scroll_area_touched_at.is_some()
|
||||
|| !mouse_over_y_scrollbar && !mouse_over_x_scrollbar =>
|
||||
{
|
||||
match event {
|
||||
touch::Event::FingerPressed { .. } => {
|
||||
state.scroll_area_touched_at = Some(cursor_position);
|
||||
}
|
||||
touch::Event::FingerMoved { .. } => {
|
||||
if let Some(scroll_box_touched_at) =
|
||||
state.scroll_area_touched_at
|
||||
{
|
||||
let delta = Vector::new(
|
||||
cursor_position.x - scroll_box_touched_at.x,
|
||||
cursor_position.y - scroll_box_touched_at.y,
|
||||
);
|
||||
|
||||
state.scroll(delta, bounds, content_bounds);
|
||||
|
||||
return event::Status::Captured;
|
||||
}
|
||||
Event::Touch(event)
|
||||
if state.scroll_area_touched_at.is_some()
|
||||
|| !mouse_over_y_scrollbar && !mouse_over_x_scrollbar =>
|
||||
{
|
||||
match event {
|
||||
touch::Event::FingerPressed { .. } => {
|
||||
state.scroll_area_touched_at = Some(cursor_position);
|
||||
}
|
||||
touch::Event::FingerMoved { .. } => {
|
||||
if let Some(scroll_box_touched_at) =
|
||||
state.scroll_area_touched_at
|
||||
{
|
||||
let delta = Vector::new(
|
||||
cursor_position.x - scroll_box_touched_at.x,
|
||||
cursor_position.y - scroll_box_touched_at.y,
|
||||
);
|
||||
|
||||
state.scroll(delta, bounds, content_bounds);
|
||||
|
||||
state.scroll_area_touched_at =
|
||||
Some(cursor_position);
|
||||
|
||||
notify_on_scroll(
|
||||
state,
|
||||
on_scroll,
|
||||
bounds,
|
||||
content_bounds,
|
||||
shell,
|
||||
);
|
||||
}
|
||||
}
|
||||
touch::Event::FingerLifted { .. }
|
||||
| touch::Event::FingerLost { .. } => {
|
||||
state.scroll_area_touched_at = None;
|
||||
notify_on_scroll(
|
||||
state,
|
||||
on_scroll,
|
||||
bounds,
|
||||
content_bounds,
|
||||
shell,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return event::Status::Captured;
|
||||
touch::Event::FingerLifted { .. }
|
||||
| touch::Event::FingerLost { .. } => {
|
||||
state.scroll_area_touched_at = None;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
return event::Status::Captured;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if let Some(scroller_grabbed_at) = state.y_scroller_grabbed_at {
|
||||
|
|
@ -700,17 +688,17 @@ pub fn update<Message>(
|
|||
pub fn mouse_interaction(
|
||||
state: &State,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
cursor: mouse::Cursor,
|
||||
vertical: &Properties,
|
||||
horizontal: Option<&Properties>,
|
||||
content_interaction: impl FnOnce(
|
||||
Layout<'_>,
|
||||
Point,
|
||||
mouse::Cursor,
|
||||
&Rectangle,
|
||||
) -> mouse::Interaction,
|
||||
) -> mouse::Interaction {
|
||||
let bounds = layout.bounds();
|
||||
let mouse_over_scrollable = bounds.contains(cursor_position);
|
||||
let cursor_over_scrollable = cursor.position_over(&bounds);
|
||||
|
||||
let content_layout = layout.children().next().unwrap();
|
||||
let content_bounds = content_layout.bounds();
|
||||
|
|
@ -719,7 +707,7 @@ pub fn mouse_interaction(
|
|||
Scrollbars::new(state, vertical, horizontal, bounds, content_bounds);
|
||||
|
||||
let (mouse_over_y_scrollbar, mouse_over_x_scrollbar) =
|
||||
scrollbars.is_mouse_over(cursor_position);
|
||||
scrollbars.is_mouse_over(cursor);
|
||||
|
||||
if (mouse_over_x_scrollbar || mouse_over_y_scrollbar)
|
||||
|| state.scrollers_grabbed()
|
||||
|
|
@ -728,17 +716,18 @@ pub fn mouse_interaction(
|
|||
} else {
|
||||
let offset = state.offset(bounds, content_bounds);
|
||||
|
||||
let cursor_position = if mouse_over_scrollable
|
||||
&& !(mouse_over_y_scrollbar || mouse_over_x_scrollbar)
|
||||
{
|
||||
cursor_position + offset
|
||||
} else {
|
||||
Point::new(-1.0, -1.0)
|
||||
let cursor = match cursor_over_scrollable {
|
||||
Some(cursor_position)
|
||||
if !(mouse_over_x_scrollbar || mouse_over_y_scrollbar) =>
|
||||
{
|
||||
mouse::Cursor::Available(cursor_position + offset)
|
||||
}
|
||||
_ => mouse::Cursor::Unavailable,
|
||||
};
|
||||
|
||||
content_interaction(
|
||||
content_layout,
|
||||
cursor_position,
|
||||
cursor,
|
||||
&Rectangle {
|
||||
y: bounds.y + offset.y,
|
||||
x: bounds.x + offset.x,
|
||||
|
|
@ -754,11 +743,11 @@ pub fn draw<Renderer>(
|
|||
renderer: &mut Renderer,
|
||||
theme: &Renderer::Theme,
|
||||
layout: Layout<'_>,
|
||||
cursor_position: Point,
|
||||
cursor: mouse::Cursor,
|
||||
vertical: &Properties,
|
||||
horizontal: Option<&Properties>,
|
||||
style: &<Renderer::Theme as StyleSheet>::Style,
|
||||
draw_content: impl FnOnce(&mut Renderer, Layout<'_>, Point, &Rectangle),
|
||||
draw_content: impl FnOnce(&mut Renderer, Layout<'_>, mouse::Cursor, &Rectangle),
|
||||
) where
|
||||
Renderer: crate::core::Renderer,
|
||||
Renderer::Theme: StyleSheet,
|
||||
|
|
@ -770,18 +759,19 @@ pub fn draw<Renderer>(
|
|||
let scrollbars =
|
||||
Scrollbars::new(state, vertical, horizontal, bounds, content_bounds);
|
||||
|
||||
let mouse_over_scrollable = bounds.contains(cursor_position);
|
||||
let cursor_over_scrollable = cursor.position_over(&bounds);
|
||||
let (mouse_over_y_scrollbar, mouse_over_x_scrollbar) =
|
||||
scrollbars.is_mouse_over(cursor_position);
|
||||
scrollbars.is_mouse_over(cursor);
|
||||
|
||||
let offset = state.offset(bounds, content_bounds);
|
||||
|
||||
let cursor_position = if mouse_over_scrollable
|
||||
&& !(mouse_over_x_scrollbar || mouse_over_y_scrollbar)
|
||||
{
|
||||
cursor_position + offset
|
||||
} else {
|
||||
Point::new(-1.0, -1.0)
|
||||
let cursor = match cursor_over_scrollable {
|
||||
Some(cursor_position)
|
||||
if !(mouse_over_x_scrollbar || mouse_over_y_scrollbar) =>
|
||||
{
|
||||
mouse::Cursor::Available(cursor_position + offset)
|
||||
}
|
||||
_ => mouse::Cursor::Unavailable,
|
||||
};
|
||||
|
||||
// Draw inner content
|
||||
|
|
@ -793,7 +783,7 @@ pub fn draw<Renderer>(
|
|||
draw_content(
|
||||
renderer,
|
||||
content_layout,
|
||||
cursor_position,
|
||||
cursor,
|
||||
&Rectangle {
|
||||
y: bounds.y + offset.y,
|
||||
x: bounds.x + offset.x,
|
||||
|
|
@ -858,7 +848,7 @@ pub fn draw<Renderer>(
|
|||
if let Some(scrollbar) = scrollbars.y {
|
||||
let style = if state.y_scroller_grabbed_at.is_some() {
|
||||
theme.dragging(style)
|
||||
} else if mouse_over_scrollable {
|
||||
} else if cursor_over_scrollable.is_some() {
|
||||
theme.hovered(style, mouse_over_y_scrollbar)
|
||||
} else {
|
||||
theme.active(style)
|
||||
|
|
@ -871,7 +861,7 @@ pub fn draw<Renderer>(
|
|||
if let Some(scrollbar) = scrollbars.x {
|
||||
let style = if state.x_scroller_grabbed_at.is_some() {
|
||||
theme.dragging_horizontal(style)
|
||||
} else if mouse_over_scrollable {
|
||||
} else if cursor_over_scrollable.is_some() {
|
||||
theme.hovered_horizontal(style, mouse_over_x_scrollbar)
|
||||
} else {
|
||||
theme.active_horizontal(style)
|
||||
|
|
@ -885,7 +875,7 @@ pub fn draw<Renderer>(
|
|||
draw_content(
|
||||
renderer,
|
||||
content_layout,
|
||||
cursor_position,
|
||||
cursor,
|
||||
&Rectangle {
|
||||
x: bounds.x + offset.x,
|
||||
y: bounds.y + offset.y,
|
||||
|
|
@ -1283,17 +1273,21 @@ impl Scrollbars {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_mouse_over(&self, cursor_position: Point) -> (bool, bool) {
|
||||
(
|
||||
self.y
|
||||
.as_ref()
|
||||
.map(|scrollbar| scrollbar.is_mouse_over(cursor_position))
|
||||
.unwrap_or(false),
|
||||
self.x
|
||||
.as_ref()
|
||||
.map(|scrollbar| scrollbar.is_mouse_over(cursor_position))
|
||||
.unwrap_or(false),
|
||||
)
|
||||
fn is_mouse_over(&self, cursor: mouse::Cursor) -> (bool, bool) {
|
||||
if let Some(cursor_position) = cursor.position() {
|
||||
(
|
||||
self.y
|
||||
.as_ref()
|
||||
.map(|scrollbar| scrollbar.is_mouse_over(cursor_position))
|
||||
.unwrap_or(false),
|
||||
self.x
|
||||
.as_ref()
|
||||
.map(|scrollbar| scrollbar.is_mouse_over(cursor_position))
|
||||
.unwrap_or(false),
|
||||
)
|
||||
} else {
|
||||
(false, false)
|
||||
}
|
||||
}
|
||||
|
||||
fn grab_y_scroller(&self, cursor_position: Point) -> Option<f32> {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue