Introduce opaque widget helper
This commit is contained in:
parent
9492da11d9
commit
4cd45643d7
13 changed files with 182 additions and 12 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum Interaction {
|
pub enum Interaction {
|
||||||
#[default]
|
#[default]
|
||||||
|
None,
|
||||||
Idle,
|
Idle,
|
||||||
Pointer,
|
Pointer,
|
||||||
Grab,
|
Grab,
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ where
|
||||||
_viewport: &Rectangle,
|
_viewport: &Rectangle,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
) -> mouse::Interaction {
|
) -> mouse::Interaction {
|
||||||
mouse::Interaction::Idle
|
mouse::Interaction::None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the cursor is over the [`Overlay`].
|
/// Returns true if the cursor is over the [`Overlay`].
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ where
|
||||||
_viewport: &Rectangle,
|
_viewport: &Rectangle,
|
||||||
_renderer: &Renderer,
|
_renderer: &Renderer,
|
||||||
) -> mouse::Interaction {
|
) -> mouse::Interaction {
|
||||||
mouse::Interaction::Idle
|
mouse::Interaction::None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the overlay of the [`Widget`], if there is any.
|
/// Returns the overlay of the [`Widget`], if there is any.
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ mod loupe {
|
||||||
if cursor.is_over(layout.bounds()) {
|
if cursor.is_over(layout.bounds()) {
|
||||||
mouse::Interaction::ZoomIn
|
mouse::Interaction::ZoomIn
|
||||||
} else {
|
} else {
|
||||||
mouse::Interaction::Idle
|
mouse::Interaction::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ where
|
||||||
caches,
|
caches,
|
||||||
queued_events: Vec::new(),
|
queued_events: Vec::new(),
|
||||||
queued_messages: Vec::new(),
|
queued_messages: Vec::new(),
|
||||||
mouse_interaction: mouse::Interaction::Idle,
|
mouse_interaction: mouse::Interaction::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ where
|
||||||
cache,
|
cache,
|
||||||
queued_events: Vec::new(),
|
queued_events: Vec::new(),
|
||||||
queued_messages: Vec::new(),
|
queued_messages: Vec::new(),
|
||||||
mouse_interaction: mouse::Interaction::Idle,
|
mouse_interaction: mouse::Interaction::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ use crate::combo_box::{self, ComboBox};
|
||||||
use crate::container::{self, Container};
|
use crate::container::{self, Container};
|
||||||
use crate::core;
|
use crate::core;
|
||||||
use crate::core::widget::operation;
|
use crate::core::widget::operation;
|
||||||
use crate::core::{Element, Length, Pixels};
|
use crate::core::{Element, Length, Pixels, Widget};
|
||||||
use crate::keyed;
|
use crate::keyed;
|
||||||
use crate::overlay;
|
use crate::overlay;
|
||||||
use crate::pick_list::{self, PickList};
|
use crate::pick_list::{self, PickList};
|
||||||
|
|
@ -123,6 +123,173 @@ where
|
||||||
Stack::with_children(children)
|
Stack::with_children(children)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wraps the given widget and captures any mouse button presses inside the bounds of
|
||||||
|
/// the widget—therefore making it _opaque_.
|
||||||
|
///
|
||||||
|
/// This helper is meant to be used to mark elements in a [`Stack`] to avoid mouse
|
||||||
|
/// events from passing through layers.
|
||||||
|
///
|
||||||
|
/// [`Stack`]: crate::Stack
|
||||||
|
pub fn opaque<'a, Message, Theme, Renderer>(
|
||||||
|
content: impl Into<Element<'a, Message, Theme, Renderer>>,
|
||||||
|
) -> Element<'a, Message, Theme, Renderer>
|
||||||
|
where
|
||||||
|
Message: 'a,
|
||||||
|
Theme: 'a,
|
||||||
|
Renderer: core::Renderer + 'a,
|
||||||
|
{
|
||||||
|
use crate::core::event::{self, Event};
|
||||||
|
use crate::core::layout::{self, Layout};
|
||||||
|
use crate::core::mouse;
|
||||||
|
use crate::core::renderer;
|
||||||
|
use crate::core::widget::tree::{self, Tree};
|
||||||
|
use crate::core::{Rectangle, Shell, Size};
|
||||||
|
|
||||||
|
struct Opaque<'a, Message, Theme, Renderer> {
|
||||||
|
content: Element<'a, Message, Theme, Renderer>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
|
||||||
|
for Opaque<'a, Message, Theme, Renderer>
|
||||||
|
where
|
||||||
|
Renderer: core::Renderer,
|
||||||
|
{
|
||||||
|
fn tag(&self) -> tree::Tag {
|
||||||
|
self.content.as_widget().tag()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn state(&self) -> tree::State {
|
||||||
|
self.content.as_widget().state()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn children(&self) -> Vec<Tree> {
|
||||||
|
self.content.as_widget().children()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn diff(&self, tree: &mut Tree) {
|
||||||
|
self.content.as_widget().diff(tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> Size<Length> {
|
||||||
|
self.content.as_widget().size()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_hint(&self) -> Size<Length> {
|
||||||
|
self.content.as_widget().size_hint()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layout(
|
||||||
|
&self,
|
||||||
|
tree: &mut Tree,
|
||||||
|
renderer: &Renderer,
|
||||||
|
limits: &layout::Limits,
|
||||||
|
) -> layout::Node {
|
||||||
|
self.content.as_widget().layout(tree, renderer, limits)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(
|
||||||
|
&self,
|
||||||
|
tree: &Tree,
|
||||||
|
renderer: &mut Renderer,
|
||||||
|
theme: &Theme,
|
||||||
|
style: &renderer::Style,
|
||||||
|
layout: Layout<'_>,
|
||||||
|
cursor: mouse::Cursor,
|
||||||
|
viewport: &Rectangle,
|
||||||
|
) {
|
||||||
|
self.content
|
||||||
|
.as_widget()
|
||||||
|
.draw(tree, renderer, theme, style, layout, cursor, viewport);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn operate(
|
||||||
|
&self,
|
||||||
|
state: &mut Tree,
|
||||||
|
layout: Layout<'_>,
|
||||||
|
renderer: &Renderer,
|
||||||
|
operation: &mut dyn operation::Operation<Message>,
|
||||||
|
) {
|
||||||
|
self.content
|
||||||
|
.as_widget()
|
||||||
|
.operate(state, layout, renderer, operation);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_event(
|
||||||
|
&mut self,
|
||||||
|
state: &mut Tree,
|
||||||
|
event: Event,
|
||||||
|
layout: Layout<'_>,
|
||||||
|
cursor: mouse::Cursor,
|
||||||
|
renderer: &Renderer,
|
||||||
|
clipboard: &mut dyn core::Clipboard,
|
||||||
|
shell: &mut Shell<'_, Message>,
|
||||||
|
viewport: &Rectangle,
|
||||||
|
) -> event::Status {
|
||||||
|
let is_mouse_press = matches!(
|
||||||
|
event,
|
||||||
|
core::Event::Mouse(mouse::Event::ButtonPressed(_))
|
||||||
|
);
|
||||||
|
|
||||||
|
if let core::event::Status::Captured =
|
||||||
|
self.content.as_widget_mut().on_event(
|
||||||
|
state, event, layout, cursor, renderer, clipboard, shell,
|
||||||
|
viewport,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return event::Status::Captured;
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_mouse_press && cursor.is_over(layout.bounds()) {
|
||||||
|
event::Status::Captured
|
||||||
|
} else {
|
||||||
|
event::Status::Ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mouse_interaction(
|
||||||
|
&self,
|
||||||
|
state: &core::widget::Tree,
|
||||||
|
layout: core::Layout<'_>,
|
||||||
|
cursor: core::mouse::Cursor,
|
||||||
|
viewport: &core::Rectangle,
|
||||||
|
renderer: &Renderer,
|
||||||
|
) -> core::mouse::Interaction {
|
||||||
|
let interaction = self
|
||||||
|
.content
|
||||||
|
.as_widget()
|
||||||
|
.mouse_interaction(state, layout, cursor, viewport, renderer);
|
||||||
|
|
||||||
|
if interaction == mouse::Interaction::None
|
||||||
|
&& cursor.is_over(layout.bounds())
|
||||||
|
{
|
||||||
|
mouse::Interaction::Idle
|
||||||
|
} else {
|
||||||
|
interaction
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn overlay<'b>(
|
||||||
|
&'b mut self,
|
||||||
|
state: &'b mut core::widget::Tree,
|
||||||
|
layout: core::Layout<'_>,
|
||||||
|
renderer: &Renderer,
|
||||||
|
translation: core::Vector,
|
||||||
|
) -> Option<core::overlay::Element<'b, Message, Theme, Renderer>>
|
||||||
|
{
|
||||||
|
self.content.as_widget_mut().overlay(
|
||||||
|
state,
|
||||||
|
layout,
|
||||||
|
renderer,
|
||||||
|
translation,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Element::new(Opaque {
|
||||||
|
content: content.into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new [`Scrollable`] with the provided content.
|
/// Creates a new [`Scrollable`] with the provided content.
|
||||||
///
|
///
|
||||||
/// [`Scrollable`]: crate::Scrollable
|
/// [`Scrollable`]: crate::Scrollable
|
||||||
|
|
|
||||||
|
|
@ -304,7 +304,7 @@ where
|
||||||
} else if is_mouse_over {
|
} else if is_mouse_over {
|
||||||
mouse::Interaction::Grab
|
mouse::Interaction::Grab
|
||||||
} else {
|
} else {
|
||||||
mouse::Interaction::Idle
|
mouse::Interaction::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -232,7 +232,7 @@ where
|
||||||
);
|
);
|
||||||
|
|
||||||
match (self.interaction, content_interaction) {
|
match (self.interaction, content_interaction) {
|
||||||
(Some(interaction), mouse::Interaction::Idle)
|
(Some(interaction), mouse::Interaction::None)
|
||||||
if cursor.is_over(layout.bounds()) =>
|
if cursor.is_over(layout.bounds()) =>
|
||||||
{
|
{
|
||||||
interaction
|
interaction
|
||||||
|
|
|
||||||
|
|
@ -857,7 +857,7 @@ where
|
||||||
if (mouse_over_x_scrollbar || mouse_over_y_scrollbar)
|
if (mouse_over_x_scrollbar || mouse_over_y_scrollbar)
|
||||||
|| state.scrollers_grabbed()
|
|| state.scrollers_grabbed()
|
||||||
{
|
{
|
||||||
mouse::Interaction::Idle
|
mouse::Interaction::None
|
||||||
} else {
|
} else {
|
||||||
let translation =
|
let translation =
|
||||||
state.translation(self.direction, bounds, content_bounds);
|
state.translation(self.direction, bounds, content_bounds);
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,7 @@ where
|
||||||
state, layout, cursor, viewport, renderer,
|
state, layout, cursor, viewport, renderer,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.find(|&interaction| interaction != mouse::Interaction::Idle)
|
.find(|&interaction| interaction != mouse::Interaction::None)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -396,7 +396,9 @@ pub fn mouse_interaction(
|
||||||
use mouse::Interaction;
|
use mouse::Interaction;
|
||||||
|
|
||||||
match interaction {
|
match interaction {
|
||||||
Interaction::Idle => winit::window::CursorIcon::Default,
|
Interaction::None | Interaction::Idle => {
|
||||||
|
winit::window::CursorIcon::Default
|
||||||
|
}
|
||||||
Interaction::Pointer => winit::window::CursorIcon::Pointer,
|
Interaction::Pointer => winit::window::CursorIcon::Pointer,
|
||||||
Interaction::Working => winit::window::CursorIcon::Progress,
|
Interaction::Working => winit::window::CursorIcon::Progress,
|
||||||
Interaction::Grab => winit::window::CursorIcon::Grab,
|
Interaction::Grab => winit::window::CursorIcon::Grab,
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ where
|
||||||
exit_on_close_request,
|
exit_on_close_request,
|
||||||
surface,
|
surface,
|
||||||
renderer,
|
renderer,
|
||||||
mouse_interaction: mouse::Interaction::Idle,
|
mouse_interaction: mouse::Interaction::None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue