Remove now redundant Overlay::is_over

The `mouse_interaction` method can be properly used
now to encode hover status with the `None` and `Idle`
variants.
This commit is contained in:
Héctor Ramón Jiménez 2025-05-02 21:23:17 +02:00
parent a01beefa84
commit 9e934fe2a7
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
15 changed files with 92 additions and 256 deletions

View file

@ -10,7 +10,7 @@ use crate::mouse;
use crate::renderer;
use crate::widget;
use crate::widget::Tree;
use crate::{Clipboard, Event, Layout, Point, Rectangle, Shell, Size, Vector};
use crate::{Clipboard, Event, Layout, Rectangle, Shell, Size, Vector};
/// An interactive component that can be displayed on top of other widgets.
pub trait Overlay<Message, Theme, Renderer>
@ -69,30 +69,16 @@ where
/// Returns the current [`mouse::Interaction`] of the [`Overlay`].
///
/// By default, it returns [`mouse::Interaction::Idle`].
/// By default, it returns [`mouse::Interaction::None`].
fn mouse_interaction(
&self,
_layout: Layout<'_>,
_cursor: mouse::Cursor,
_viewport: &Rectangle,
_renderer: &Renderer,
) -> mouse::Interaction {
mouse::Interaction::None
}
/// Returns true if the cursor is over the [`Overlay`].
///
/// By default, it returns true if the bounds of the `layout` contain
/// the `cursor_position`.
fn is_over(
&self,
layout: Layout<'_>,
_renderer: &Renderer,
cursor_position: Point,
) -> bool {
layout.bounds().contains(cursor_position)
}
/// Returns the nested overlay of the [`Overlay`], if there is any.
fn overlay<'a>(
&'a mut self,

View file

@ -4,7 +4,7 @@ use crate::layout;
use crate::mouse;
use crate::renderer;
use crate::widget;
use crate::{Clipboard, Event, Layout, Point, Rectangle, Shell, Size};
use crate::{Clipboard, Event, Layout, Shell, Size};
/// A generic [`Overlay`].
#[allow(missing_debug_implementations)]
@ -112,11 +112,9 @@ where
&self,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.content
.mouse_interaction(layout, cursor, viewport, renderer)
self.content.mouse_interaction(layout, cursor, renderer)
}
fn draw(
@ -130,15 +128,6 @@ where
self.content.draw(renderer, theme, style, layout, cursor);
}
fn is_over(
&self,
layout: Layout<'_>,
renderer: &Renderer,
cursor_position: Point,
) -> bool {
self.content.is_over(layout, renderer, cursor_position)
}
fn overlay<'a>(
&'a mut self,
layout: Layout<'_>,

View file

@ -3,7 +3,7 @@ use crate::mouse;
use crate::overlay;
use crate::renderer;
use crate::widget;
use crate::{Clipboard, Event, Layout, Overlay, Point, Rectangle, Shell, Size};
use crate::{Clipboard, Event, Layout, Overlay, Shell, Size};
/// An [`Overlay`] container that displays multiple overlay [`overlay::Element`]
/// children.
@ -107,7 +107,6 @@ where
&self,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.children
@ -116,7 +115,7 @@ where
.map(|(child, layout)| {
child
.as_overlay()
.mouse_interaction(layout, cursor, viewport, renderer)
.mouse_interaction(layout, cursor, renderer)
})
.max()
.unwrap_or_default()
@ -137,22 +136,6 @@ where
});
}
fn is_over(
&self,
layout: Layout<'_>,
renderer: &Renderer,
cursor_position: Point,
) -> bool {
self.children
.iter()
.zip(layout.children())
.any(|(child, layout)| {
child
.as_overlay()
.is_over(layout, renderer, cursor_position)
})
}
fn overlay<'a>(
&'a mut self,
layout: Layout<'_>,

View file

@ -443,6 +443,7 @@ mod toast {
let toasts = (!self.toasts.is_empty()).then(|| {
overlay::Element::new(Box::new(Overlay {
position: layout.bounds().position() + translation,
viewport: *viewport,
toasts: &mut self.toasts,
state: toasts_state,
instants,
@ -460,6 +461,7 @@ mod toast {
struct Overlay<'a, 'b, Message> {
position: Point,
viewport: Rectangle,
toasts: &'b mut [Element<'a, Message>],
state: &'b mut [Tree],
instants: &'b mut [Option<Instant>],
@ -595,7 +597,6 @@ mod toast {
&self,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.toasts
@ -603,24 +604,25 @@ mod toast {
.zip(self.state.iter())
.zip(layout.children())
.map(|((child, state), layout)| {
child.as_widget().mouse_interaction(
state, layout, cursor, viewport, renderer,
)
child
.as_widget()
.mouse_interaction(
state,
layout,
cursor,
&self.viewport,
renderer,
)
.max(
cursor
.is_over(layout.bounds())
.then_some(mouse::Interaction::Idle)
.unwrap_or_default(),
)
})
.max()
.unwrap_or_default()
}
fn is_over(
&self,
layout: Layout<'_>,
_renderer: &Renderer,
cursor_position: Point,
) -> bool {
layout
.children()
.any(|layout| layout.bounds().contains(cursor_position))
}
}
impl<'a, Message> From<Manager<'a, Message>> for Element<'a, Message>

View file

@ -4,7 +4,7 @@ use crate::core::mouse;
use crate::core::overlay;
use crate::core::renderer;
use crate::core::widget;
use crate::core::{Clipboard, Event, Layout, Point, Rectangle, Shell, Size};
use crate::core::{Clipboard, Event, Layout, Shell, Size};
/// An overlay container that displays nested overlays
#[allow(missing_debug_implementations)]
@ -87,11 +87,11 @@ where
.zip(nested_layout)
.and_then(|(cursor_position, nested_layout)| {
overlay.overlay(layout, renderer).map(|nested| {
nested.as_overlay().is_over(
nested.as_overlay().mouse_interaction(
nested_layout.children().next().unwrap(),
mouse::Cursor::Available(cursor_position),
renderer,
cursor_position,
)
) != mouse::Interaction::None
})
})
.unwrap_or_default();
@ -209,11 +209,11 @@ where
|| cursor
.position()
.map(|cursor_position| {
overlay.is_over(
overlay.mouse_interaction(
layout,
mouse::Cursor::Available(cursor_position),
renderer,
cursor_position,
)
) != mouse::Interaction::None
})
.unwrap_or_default();
@ -255,14 +255,12 @@ where
&mut self,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
fn recurse<Message, Theme, Renderer>(
element: &mut overlay::Element<'_, Message, Theme, Renderer>,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> Option<mouse::Interaction>
where
@ -278,68 +276,14 @@ where
.overlay(layout, renderer)
.zip(layouts.next())
.and_then(|(mut overlay, layout)| {
recurse(
&mut overlay,
layout,
cursor,
viewport,
renderer,
)
recurse(&mut overlay, layout, cursor, renderer)
})
.unwrap_or_else(|| {
overlay.mouse_interaction(
layout, cursor, viewport, renderer,
)
overlay.mouse_interaction(layout, cursor, renderer)
}),
)
}
recurse(&mut self.overlay, layout, cursor, viewport, renderer)
.unwrap_or_default()
}
/// Returns true if the cursor is over the [`Nested`] overlay.
pub fn is_over(
&mut self,
layout: Layout<'_>,
renderer: &Renderer,
cursor_position: Point,
) -> bool {
fn recurse<Message, Theme, Renderer>(
element: &mut overlay::Element<'_, Message, Theme, Renderer>,
layout: Layout<'_>,
renderer: &Renderer,
cursor_position: Point,
) -> bool
where
Renderer: renderer::Renderer,
{
let mut layouts = layout.children();
if let Some(layout) = layouts.next() {
let overlay = element.as_overlay_mut();
if overlay.is_over(layout, renderer, cursor_position) {
return true;
}
if let Some((mut nested, nested_layout)) =
overlay.overlay(layout, renderer).zip(layouts.next())
{
recurse(
&mut nested,
nested_layout,
renderer,
cursor_position,
)
} else {
false
}
} else {
false
}
}
recurse(&mut self.overlay, layout, renderer, cursor_position)
recurse(&mut self.overlay, layout, cursor, renderer).unwrap_or_default()
}
}

View file

@ -270,11 +270,11 @@ where
.as_mut()
.and_then(|overlay| {
cursor.position().map(|cursor_position| {
overlay.is_over(
overlay.mouse_interaction(
Layout::new(&layout),
mouse::Cursor::Available(cursor_position),
renderer,
cursor_position,
)
) != mouse::Interaction::None
})
})
.unwrap_or_default()
@ -439,7 +439,7 @@ where
let viewport = Rectangle::with_size(self.bounds);
let base_cursor = if let Some(mut overlay) = self
let (base_cursor, overlay_interaction) = if let Some(mut overlay) = self
.root
.as_widget_mut()
.overlay(
@ -456,27 +456,31 @@ where
.take()
.unwrap_or_else(|| overlay.layout(renderer, self.bounds));
let cursor = if cursor
.position()
.map(|cursor_position| {
overlay.is_over(
Layout::new(&overlay_layout),
renderer,
cursor_position,
)
})
.unwrap_or_default()
{
mouse::Cursor::Unavailable
} else {
cursor
let (cursor, overlay_interaction) = {
let overlay_interaction =
cursor.position().map(|cursor_position| {
overlay.mouse_interaction(
Layout::new(&overlay_layout),
mouse::Cursor::Available(cursor_position),
renderer,
)
});
match overlay_interaction {
Some(mouse::Interaction::None) | None => {
(cursor, mouse::Interaction::None)
}
Some(interaction) => {
(mouse::Cursor::Unavailable, interaction)
}
}
};
self.overlay = Some(overlay_layout);
cursor
(cursor, overlay_interaction)
} else {
cursor
(cursor, mouse::Interaction::None)
};
self.root.as_widget().draw(
@ -522,13 +526,6 @@ where
)
.map(overlay::Nested::new)
.map(|mut overlay| {
let overlay_interaction = overlay.mouse_interaction(
Layout::new(layout),
cursor,
&viewport,
renderer,
);
overlay.draw(
renderer,
theme,
@ -537,8 +534,7 @@ where
cursor,
);
if overlay_interaction != mouse::Interaction::default()
{
if overlay_interaction != mouse::Interaction::None {
overlay_interaction
} else {
base_interaction

View file

@ -836,7 +836,7 @@ where
tree: &'b mut widget::Tree,
layout: Layout<'_>,
_renderer: &Renderer,
_viewport: &Rectangle,
viewport: &Rectangle,
translation: Vector,
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
let is_focused = {
@ -889,12 +889,11 @@ where
menu = menu.text_size(size);
}
Some(
menu.overlay(
layout.position() + translation,
bounds.height,
),
)
Some(menu.overlay(
layout.position() + translation,
*viewport,
bounds.height,
))
}
} else {
None

View file

@ -8,8 +8,8 @@ use crate::core::renderer;
use crate::core::widget;
use crate::core::widget::tree;
use crate::core::{
Clipboard, Element, Event, Layout, Length, Point, Rectangle, Shadow, Shell,
Size, Transformation, Vector, Widget,
Clipboard, Element, Event, Layout, Length, Rectangle, Shadow, Shell, Size,
Transformation, Vector, Widget,
};
/// A widget that can make its contents float over other widgets.
@ -298,18 +298,6 @@ where
layout::Node::new(bounds.size()).move_to(bounds.position())
}
fn is_over(
&self,
layout: Layout<'_>,
_renderer: &Renderer,
cursor_position: Point,
) -> bool {
self.float.opaque
&& layout
.bounds()
.contains(cursor_position * self.transformation.inverse())
}
fn update(
&mut self,
event: &Event,
@ -379,7 +367,6 @@ where
&self,
_layout: Layout<'_>,
cursor: mouse::Cursor,
_viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.float.content.as_widget().mouse_interaction(

View file

@ -18,7 +18,7 @@ use crate::core::renderer;
use crate::core::widget::tree::{self, Tree};
use crate::core::widget::{self, Widget};
use crate::core::{
self, Clipboard, Event, Length, Point, Rectangle, Shell, Size, Vector,
self, Clipboard, Event, Length, Rectangle, Shell, Size, Vector,
};
use crate::runtime::overlay::Nested;
@ -378,11 +378,10 @@ where
&self,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.with_overlay_maybe(|overlay| {
overlay.mouse_interaction(layout, cursor, viewport, renderer)
overlay.mouse_interaction(layout, cursor, renderer)
})
.unwrap_or_default()
}
@ -400,18 +399,6 @@ where
overlay.update(event, layout, cursor, renderer, clipboard, shell);
});
}
fn is_over(
&self,
layout: Layout<'_>,
renderer: &Renderer,
cursor_position: Point,
) -> bool {
self.with_overlay_maybe(|overlay| {
overlay.is_over(layout, renderer, cursor_position)
})
.unwrap_or_default()
}
}
impl<'a, Message, Theme, Renderer, Dependency, View>

View file

@ -7,8 +7,7 @@ use crate::core::renderer;
use crate::core::widget;
use crate::core::widget::tree::{self, Tree};
use crate::core::{
self, Clipboard, Element, Length, Point, Rectangle, Shell, Size, Vector,
Widget,
self, Clipboard, Element, Length, Rectangle, Shell, Size, Vector, Widget,
};
use crate::runtime::overlay::Nested;
@ -590,11 +589,10 @@ where
&self,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.with_overlay_maybe(|overlay| {
overlay.mouse_interaction(layout, cursor, viewport, renderer)
overlay.mouse_interaction(layout, cursor, renderer)
})
.unwrap_or_default()
}
@ -666,16 +664,4 @@ where
shell.invalidate_layout();
}
}
fn is_over(
&self,
layout: Layout<'_>,
renderer: &Renderer,
cursor_position: Point,
) -> bool {
self.with_overlay_maybe(|overlay| {
overlay.is_over(layout, renderer, cursor_position)
})
.unwrap_or_default()
}
}

View file

@ -416,11 +416,10 @@ where
&self,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.with_overlay_maybe(|overlay| {
overlay.mouse_interaction(layout, cursor, viewport, renderer)
overlay.mouse_interaction(layout, cursor, renderer)
})
.unwrap_or_default()
}
@ -449,18 +448,6 @@ where
}
}
fn is_over(
&self,
layout: Layout<'_>,
renderer: &Renderer,
cursor_position: Point,
) -> bool {
self.with_overlay_maybe(|overlay| {
overlay.is_over(layout, renderer, cursor_position)
})
.unwrap_or_default()
}
fn operate(
&mut self,
layout: Layout<'_>,

View file

@ -127,10 +127,12 @@ where
pub fn overlay(
self,
position: Point,
viewport: Rectangle,
target_height: f32,
) -> overlay::Element<'a, Message, Theme, Renderer> {
overlay::Element::new(Box::new(Overlay::new(
position,
viewport,
self,
target_height,
)))
@ -164,6 +166,7 @@ where
Renderer: crate::core::Renderer,
{
position: Point,
viewport: Rectangle,
state: &'a mut Tree,
list: Scrollable<'a, Message, Theme, Renderer>,
width: f32,
@ -180,6 +183,7 @@ where
{
pub fn new<T>(
position: Point,
viewport: Rectangle,
menu: Menu<'a, 'b, T, Message, Theme, Renderer>,
target_height: f32,
) -> Self
@ -218,6 +222,7 @@ where
Self {
position,
viewport,
state: &mut state.tree,
list,
width,
@ -282,11 +287,15 @@ where
&self,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.list
.mouse_interaction(self.state, layout, cursor, viewport, renderer)
self.list.mouse_interaction(
self.state,
layout,
cursor,
&self.viewport,
renderer,
)
}
fn draw(

View file

@ -690,7 +690,7 @@ where
tree: &'b mut Tree,
layout: Layout<'_>,
renderer: &Renderer,
_viewport: &Rectangle,
viewport: &Rectangle,
translation: Vector,
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
let state = tree.state.downcast_mut::<State<Renderer::Paragraph>>();
@ -722,7 +722,11 @@ where
menu = menu.text_size(text_size);
}
Some(menu.overlay(layout.position() + translation, bounds.height))
Some(menu.overlay(
layout.position() + translation,
*viewport,
bounds.height,
))
} else {
None
}

View file

@ -6,8 +6,8 @@ use crate::core::renderer;
use crate::core::widget::Operation;
use crate::core::widget::tree::{self, Tree};
use crate::core::{
Background, Clipboard, Color, Element, Event, Layout, Length, Point,
Rectangle, Shell, Size, Vector, Widget,
Background, Clipboard, Color, Element, Event, Layout, Length, Rectangle,
Shell, Size, Vector, Widget,
};
use std::marker::PhantomData;
@ -248,25 +248,11 @@ where
&self,
layout: Layout<'_>,
cursor: mouse::Cursor,
viewport: &Rectangle,
renderer: &Renderer,
) -> mouse::Interaction {
self.content
.as_overlay()
.mouse_interaction(layout, cursor, viewport, renderer)
}
fn is_over(
&self,
layout: Layout<'_>,
renderer: &Renderer,
cursor_position: Point,
) -> bool {
self.content.as_overlay().is_over(
layout,
renderer,
cursor_position,
)
.mouse_interaction(layout, cursor, renderer)
}
fn overlay<'b>(

View file

@ -508,13 +508,4 @@ where
&Rectangle::with_size(Size::INFINITY),
);
}
fn is_over(
&self,
_layout: Layout<'_>,
_renderer: &Renderer,
_cursor_position: Point,
) -> bool {
false
}
}