Decouple mouse::Interaction from UserInterface::draw
This commit is contained in:
parent
87afd5b79d
commit
301aac794b
6 changed files with 171 additions and 187 deletions
|
|
@ -122,7 +122,7 @@ fn benchmark<'a>(
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = user_interface.draw(
|
user_interface.draw(
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
&Theme::Dark,
|
&Theme::Dark,
|
||||||
&core::renderer::Style {
|
&core::renderer::Style {
|
||||||
|
|
|
||||||
|
|
@ -268,7 +268,7 @@ pub fn main() -> Result<(), winit::error::EventLoopError> {
|
||||||
renderer,
|
renderer,
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = interface.update(
|
let (state, _) = interface.update(
|
||||||
&[Event::Window(
|
&[Event::Window(
|
||||||
window::Event::RedrawRequested(
|
window::Event::RedrawRequested(
|
||||||
Instant::now(),
|
Instant::now(),
|
||||||
|
|
@ -280,7 +280,21 @@ pub fn main() -> Result<(), winit::error::EventLoopError> {
|
||||||
&mut Vec::new(),
|
&mut Vec::new(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mouse_interaction = interface.draw(
|
// Update the mouse cursor
|
||||||
|
if let user_interface::State::Updated {
|
||||||
|
mouse_interaction,
|
||||||
|
..
|
||||||
|
} = state
|
||||||
|
{
|
||||||
|
window.set_cursor(
|
||||||
|
conversion::mouse_interaction(
|
||||||
|
mouse_interaction,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw the interface
|
||||||
|
interface.draw(
|
||||||
renderer,
|
renderer,
|
||||||
&Theme::Dark,
|
&Theme::Dark,
|
||||||
&renderer::Style::default(),
|
&renderer::Style::default(),
|
||||||
|
|
@ -297,11 +311,6 @@ pub fn main() -> Result<(), winit::error::EventLoopError> {
|
||||||
|
|
||||||
// Present the frame
|
// Present the frame
|
||||||
frame.present();
|
frame.present();
|
||||||
|
|
||||||
// Update the mouse cursor
|
|
||||||
window.set_cursor(conversion::mouse_interaction(
|
|
||||||
mouse_interaction,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Err(error) => match error {
|
Err(error) => match error {
|
||||||
wgpu::SurfaceError::OutOfMemory => {
|
wgpu::SurfaceError::OutOfMemory => {
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,15 @@ pub struct UserInterface<'a, Message, Theme, Renderer> {
|
||||||
root: Element<'a, Message, Theme, Renderer>,
|
root: Element<'a, Message, Theme, Renderer>,
|
||||||
base: layout::Node,
|
base: layout::Node,
|
||||||
state: widget::Tree,
|
state: widget::Tree,
|
||||||
overlay: Option<layout::Node>,
|
overlay: Option<Overlay>,
|
||||||
bounds: Size,
|
bounds: Size,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Overlay {
|
||||||
|
layout: layout::Node,
|
||||||
|
interaction: mouse::Interaction,
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, Message, Theme, Renderer> UserInterface<'a, Message, Theme, Renderer>
|
impl<'a, Message, Theme, Renderer> UserInterface<'a, Message, Theme, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: crate::core::Renderer,
|
Renderer: crate::core::Renderer,
|
||||||
|
|
@ -185,60 +190,58 @@ where
|
||||||
clipboard: &mut dyn Clipboard,
|
clipboard: &mut dyn Clipboard,
|
||||||
messages: &mut Vec<Message>,
|
messages: &mut Vec<Message>,
|
||||||
) -> (State, Vec<event::Status>) {
|
) -> (State, Vec<event::Status>) {
|
||||||
use std::mem::ManuallyDrop;
|
|
||||||
|
|
||||||
let mut outdated = false;
|
let mut outdated = false;
|
||||||
let mut redraw_request = window::RedrawRequest::Wait;
|
let mut redraw_request = window::RedrawRequest::Wait;
|
||||||
let mut input_method = InputMethod::Disabled;
|
let mut input_method = InputMethod::Disabled;
|
||||||
let viewport = Rectangle::with_size(self.bounds);
|
let viewport = Rectangle::with_size(self.bounds);
|
||||||
|
|
||||||
let mut manual_overlay = ManuallyDrop::new(
|
let mut maybe_overlay = self
|
||||||
self.root
|
.root
|
||||||
.as_widget_mut()
|
.as_widget_mut()
|
||||||
.overlay(
|
.overlay(
|
||||||
&mut self.state,
|
&mut self.state,
|
||||||
Layout::new(&self.base),
|
Layout::new(&self.base),
|
||||||
renderer,
|
renderer,
|
||||||
&viewport,
|
&viewport,
|
||||||
Vector::ZERO,
|
Vector::ZERO,
|
||||||
)
|
)
|
||||||
.map(overlay::Nested::new),
|
.map(overlay::Nested::new);
|
||||||
);
|
|
||||||
|
|
||||||
let (base_cursor, overlay_statuses) = if manual_overlay.is_some() {
|
let (base_cursor, overlay_statuses, overlay_interaction) =
|
||||||
let bounds = self.bounds;
|
if maybe_overlay.is_some() {
|
||||||
|
let bounds = self.bounds;
|
||||||
|
|
||||||
let mut overlay = manual_overlay.as_mut().unwrap();
|
let mut overlay = maybe_overlay.as_mut().unwrap();
|
||||||
let mut layout = overlay.layout(renderer, bounds);
|
let mut layout = overlay.layout(renderer, bounds);
|
||||||
let mut event_statuses = Vec::new();
|
let mut event_statuses = Vec::new();
|
||||||
|
|
||||||
for event in events {
|
for event in events {
|
||||||
let mut shell = Shell::new(messages);
|
let mut shell = Shell::new(messages);
|
||||||
|
|
||||||
overlay.update(
|
overlay.update(
|
||||||
event,
|
event,
|
||||||
Layout::new(&layout),
|
Layout::new(&layout),
|
||||||
cursor,
|
cursor,
|
||||||
renderer,
|
|
||||||
clipboard,
|
|
||||||
&mut shell,
|
|
||||||
);
|
|
||||||
|
|
||||||
event_statuses.push(shell.event_status());
|
|
||||||
redraw_request = redraw_request.min(shell.redraw_request());
|
|
||||||
input_method.merge(shell.input_method());
|
|
||||||
|
|
||||||
if shell.is_layout_invalid() {
|
|
||||||
let _ = ManuallyDrop::into_inner(manual_overlay);
|
|
||||||
|
|
||||||
self.base = self.root.as_widget().layout(
|
|
||||||
&mut self.state,
|
|
||||||
renderer,
|
renderer,
|
||||||
&layout::Limits::new(Size::ZERO, self.bounds),
|
clipboard,
|
||||||
|
&mut shell,
|
||||||
);
|
);
|
||||||
|
|
||||||
manual_overlay = ManuallyDrop::new(
|
event_statuses.push(shell.event_status());
|
||||||
self.root
|
redraw_request = redraw_request.min(shell.redraw_request());
|
||||||
|
input_method.merge(shell.input_method());
|
||||||
|
|
||||||
|
if shell.is_layout_invalid() {
|
||||||
|
drop(maybe_overlay);
|
||||||
|
|
||||||
|
self.base = self.root.as_widget().layout(
|
||||||
|
&mut self.state,
|
||||||
|
renderer,
|
||||||
|
&layout::Limits::new(Size::ZERO, self.bounds),
|
||||||
|
);
|
||||||
|
|
||||||
|
maybe_overlay = self
|
||||||
|
.root
|
||||||
.as_widget_mut()
|
.as_widget_mut()
|
||||||
.overlay(
|
.overlay(
|
||||||
&mut self.state,
|
&mut self.state,
|
||||||
|
|
@ -247,53 +250,61 @@ where
|
||||||
&viewport,
|
&viewport,
|
||||||
Vector::ZERO,
|
Vector::ZERO,
|
||||||
)
|
)
|
||||||
.map(overlay::Nested::new),
|
.map(overlay::Nested::new);
|
||||||
);
|
|
||||||
|
|
||||||
if manual_overlay.is_none() {
|
if maybe_overlay.is_none() {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
overlay = maybe_overlay.as_mut().unwrap();
|
||||||
|
|
||||||
|
shell.revalidate_layout(|| {
|
||||||
|
layout = overlay.layout(renderer, bounds);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
overlay = manual_overlay.as_mut().unwrap();
|
if shell.are_widgets_invalid() {
|
||||||
|
outdated = true;
|
||||||
shell.revalidate_layout(|| {
|
}
|
||||||
layout = overlay.layout(renderer, bounds);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if shell.are_widgets_invalid() {
|
let (base_cursor, interaction) =
|
||||||
outdated = true;
|
if let Some(overlay) = maybe_overlay.as_mut() {
|
||||||
}
|
let interaction = cursor
|
||||||
}
|
.position()
|
||||||
|
.map(|cursor_position| {
|
||||||
|
overlay.mouse_interaction(
|
||||||
|
Layout::new(&layout),
|
||||||
|
mouse::Cursor::Available(cursor_position),
|
||||||
|
renderer,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
let base_cursor = if manual_overlay
|
if interaction == mouse::Interaction::None {
|
||||||
.as_mut()
|
(cursor, mouse::Interaction::None)
|
||||||
.and_then(|overlay| {
|
} else {
|
||||||
cursor.position().map(|cursor_position| {
|
(mouse::Cursor::Unavailable, interaction)
|
||||||
overlay.mouse_interaction(
|
}
|
||||||
Layout::new(&layout),
|
} else {
|
||||||
mouse::Cursor::Available(cursor_position),
|
(cursor, mouse::Interaction::None)
|
||||||
renderer,
|
};
|
||||||
) != mouse::Interaction::None
|
|
||||||
})
|
self.overlay = Some(Overlay {
|
||||||
})
|
layout,
|
||||||
.unwrap_or_default()
|
interaction,
|
||||||
{
|
});
|
||||||
mouse::Cursor::Unavailable
|
|
||||||
|
(base_cursor, event_statuses, interaction)
|
||||||
} else {
|
} else {
|
||||||
cursor
|
(
|
||||||
|
cursor,
|
||||||
|
vec![event::Status::Ignored; events.len()],
|
||||||
|
mouse::Interaction::None,
|
||||||
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.overlay = Some(layout);
|
drop(maybe_overlay);
|
||||||
|
|
||||||
(base_cursor, event_statuses)
|
|
||||||
} else {
|
|
||||||
(cursor, vec![event::Status::Ignored; events.len()])
|
|
||||||
};
|
|
||||||
|
|
||||||
let viewport = Rectangle::with_size(self.bounds);
|
|
||||||
|
|
||||||
let _ = ManuallyDrop::into_inner(manual_overlay);
|
|
||||||
|
|
||||||
let event_statuses = events
|
let event_statuses = events
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -341,11 +352,25 @@ where
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let mouse_interaction =
|
||||||
|
if overlay_interaction == mouse::Interaction::None {
|
||||||
|
self.root.as_widget().mouse_interaction(
|
||||||
|
&self.state,
|
||||||
|
Layout::new(&self.base),
|
||||||
|
base_cursor,
|
||||||
|
&viewport,
|
||||||
|
renderer,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
overlay_interaction
|
||||||
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
if outdated {
|
if outdated {
|
||||||
State::Outdated
|
State::Outdated
|
||||||
} else {
|
} else {
|
||||||
State::Updated {
|
State::Updated {
|
||||||
|
mouse_interaction,
|
||||||
redraw_request,
|
redraw_request,
|
||||||
input_method,
|
input_method,
|
||||||
}
|
}
|
||||||
|
|
@ -433,54 +458,19 @@ where
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
style: &renderer::Style,
|
style: &renderer::Style,
|
||||||
cursor: mouse::Cursor,
|
cursor: mouse::Cursor,
|
||||||
) -> mouse::Interaction {
|
) {
|
||||||
// TODO: Move to shell level (?)
|
// TODO: Move to shell level (?)
|
||||||
renderer.clear();
|
renderer.clear();
|
||||||
|
|
||||||
let viewport = Rectangle::with_size(self.bounds);
|
let viewport = Rectangle::with_size(self.bounds);
|
||||||
|
|
||||||
let (base_cursor, overlay_interaction) = if let Some(mut overlay) = self
|
let base_cursor = match &self.overlay {
|
||||||
.root
|
None
|
||||||
.as_widget_mut()
|
| Some(Overlay {
|
||||||
.overlay(
|
interaction: mouse::Interaction::None,
|
||||||
&mut self.state,
|
..
|
||||||
Layout::new(&self.base),
|
}) => cursor,
|
||||||
renderer,
|
_ => mouse::Cursor::Unavailable,
|
||||||
&viewport,
|
|
||||||
Vector::ZERO,
|
|
||||||
)
|
|
||||||
.map(overlay::Nested::new)
|
|
||||||
{
|
|
||||||
let overlay_layout = self
|
|
||||||
.overlay
|
|
||||||
.take()
|
|
||||||
.unwrap_or_else(|| overlay.layout(renderer, self.bounds));
|
|
||||||
|
|
||||||
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, overlay_interaction)
|
|
||||||
} else {
|
|
||||||
(cursor, mouse::Interaction::None)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.root.as_widget().draw(
|
self.root.as_widget().draw(
|
||||||
|
|
@ -493,14 +483,6 @@ where
|
||||||
&viewport,
|
&viewport,
|
||||||
);
|
);
|
||||||
|
|
||||||
let base_interaction = self.root.as_widget().mouse_interaction(
|
|
||||||
&self.state,
|
|
||||||
Layout::new(&self.base),
|
|
||||||
base_cursor,
|
|
||||||
&viewport,
|
|
||||||
renderer,
|
|
||||||
);
|
|
||||||
|
|
||||||
let Self {
|
let Self {
|
||||||
overlay,
|
overlay,
|
||||||
root,
|
root,
|
||||||
|
|
@ -508,40 +490,24 @@ where
|
||||||
..
|
..
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
// TODO: Currently, we need to call Widget::overlay twice to
|
let Some(Overlay { layout, .. }) = overlay.as_ref() else {
|
||||||
// implement the painter's algorithm properly.
|
return;
|
||||||
//
|
};
|
||||||
// Once we have a proper persistent widget tree, we should be able to
|
|
||||||
// avoid this additional call.
|
|
||||||
overlay
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|layout| {
|
|
||||||
root.as_widget_mut()
|
|
||||||
.overlay(
|
|
||||||
&mut self.state,
|
|
||||||
Layout::new(base),
|
|
||||||
renderer,
|
|
||||||
&viewport,
|
|
||||||
Vector::ZERO,
|
|
||||||
)
|
|
||||||
.map(overlay::Nested::new)
|
|
||||||
.map(|mut overlay| {
|
|
||||||
overlay.draw(
|
|
||||||
renderer,
|
|
||||||
theme,
|
|
||||||
style,
|
|
||||||
Layout::new(layout),
|
|
||||||
cursor,
|
|
||||||
);
|
|
||||||
|
|
||||||
if overlay_interaction != mouse::Interaction::None {
|
let overlay = root
|
||||||
overlay_interaction
|
.as_widget_mut()
|
||||||
} else {
|
.overlay(
|
||||||
base_interaction
|
&mut self.state,
|
||||||
}
|
Layout::new(base),
|
||||||
})
|
renderer,
|
||||||
})
|
&viewport,
|
||||||
.unwrap_or(base_interaction)
|
Vector::ZERO,
|
||||||
|
)
|
||||||
|
.map(overlay::Nested::new);
|
||||||
|
|
||||||
|
if let Some(mut overlay) = overlay {
|
||||||
|
overlay.draw(renderer, theme, style, Layout::new(layout), cursor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Applies a [`widget::Operation`] to the [`UserInterface`].
|
/// Applies a [`widget::Operation`] to the [`UserInterface`].
|
||||||
|
|
@ -572,11 +538,14 @@ where
|
||||||
.map(overlay::Nested::new)
|
.map(overlay::Nested::new)
|
||||||
{
|
{
|
||||||
if self.overlay.is_none() {
|
if self.overlay.is_none() {
|
||||||
self.overlay = Some(overlay.layout(renderer, self.bounds));
|
self.overlay = Some(Overlay {
|
||||||
|
layout: overlay.layout(renderer, self.bounds),
|
||||||
|
interaction: mouse::Interaction::None,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
overlay.operate(
|
overlay.operate(
|
||||||
Layout::new(self.overlay.as_ref().unwrap()),
|
Layout::new(&self.overlay.as_ref().unwrap().layout),
|
||||||
renderer,
|
renderer,
|
||||||
operation,
|
operation,
|
||||||
);
|
);
|
||||||
|
|
@ -629,6 +598,8 @@ pub enum State {
|
||||||
/// The [`UserInterface`] is up-to-date and can be reused without
|
/// The [`UserInterface`] is up-to-date and can be reused without
|
||||||
/// rebuilding.
|
/// rebuilding.
|
||||||
Updated {
|
Updated {
|
||||||
|
/// The current [`mouse::Interaction`] of the user interface.
|
||||||
|
mouse_interaction: mouse::Interaction,
|
||||||
/// The [`window::RedrawRequest`] describing when a redraw should be performed.
|
/// The [`window::RedrawRequest`] describing when a redraw should be performed.
|
||||||
redraw_request: window::RedrawRequest,
|
redraw_request: window::RedrawRequest,
|
||||||
/// The current [`InputMethod`] strategy of the user interface.
|
/// The current [`InputMethod`] strategy of the user interface.
|
||||||
|
|
|
||||||
|
|
@ -436,7 +436,7 @@ where
|
||||||
&mut self.messages,
|
&mut self.messages,
|
||||||
);
|
);
|
||||||
|
|
||||||
let _ = self.raw.draw(
|
self.raw.draw(
|
||||||
&mut self.renderer,
|
&mut self.renderer,
|
||||||
theme,
|
theme,
|
||||||
&core::renderer::Style {
|
&core::renderer::Style {
|
||||||
|
|
|
||||||
|
|
@ -758,7 +758,7 @@ async fn run_instance<P>(
|
||||||
&mut messages,
|
&mut messages,
|
||||||
);
|
);
|
||||||
|
|
||||||
let new_mouse_interaction = ui.draw(
|
ui.draw(
|
||||||
&mut window.renderer,
|
&mut window.renderer,
|
||||||
window.state.theme(),
|
window.state.theme(),
|
||||||
&renderer::Style {
|
&renderer::Style {
|
||||||
|
|
@ -768,16 +768,6 @@ async fn run_instance<P>(
|
||||||
);
|
);
|
||||||
draw_span.finish();
|
draw_span.finish();
|
||||||
|
|
||||||
if new_mouse_interaction != window.mouse_interaction {
|
|
||||||
window.raw.set_cursor(
|
|
||||||
conversion::mouse_interaction(
|
|
||||||
new_mouse_interaction,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
window.mouse_interaction = new_mouse_interaction;
|
|
||||||
}
|
|
||||||
|
|
||||||
runtime.broadcast(subscription::Event::Interaction {
|
runtime.broadcast(subscription::Event::Interaction {
|
||||||
window: id,
|
window: id,
|
||||||
event: redraw_event,
|
event: redraw_event,
|
||||||
|
|
@ -787,10 +777,12 @@ async fn run_instance<P>(
|
||||||
if let user_interface::State::Updated {
|
if let user_interface::State::Updated {
|
||||||
redraw_request,
|
redraw_request,
|
||||||
input_method,
|
input_method,
|
||||||
|
mouse_interaction,
|
||||||
} = ui_state
|
} = ui_state
|
||||||
{
|
{
|
||||||
window.request_redraw(redraw_request);
|
window.request_redraw(redraw_request);
|
||||||
window.request_input_method(input_method);
|
window.request_input_method(input_method);
|
||||||
|
window.update_mouse(mouse_interaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.draw_preedit();
|
window.draw_preedit();
|
||||||
|
|
@ -944,8 +936,11 @@ async fn run_instance<P>(
|
||||||
match ui_state {
|
match ui_state {
|
||||||
user_interface::State::Updated {
|
user_interface::State::Updated {
|
||||||
redraw_request: _redraw_request,
|
redraw_request: _redraw_request,
|
||||||
|
mouse_interaction,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
|
window.update_mouse(mouse_interaction);
|
||||||
|
|
||||||
#[cfg(not(
|
#[cfg(not(
|
||||||
feature = "unconditional-rendering"
|
feature = "unconditional-rendering"
|
||||||
))]
|
))]
|
||||||
|
|
|
||||||
|
|
@ -246,6 +246,15 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_mouse(&mut self, interaction: mouse::Interaction) {
|
||||||
|
if interaction != self.mouse_interaction {
|
||||||
|
self.raw
|
||||||
|
.set_cursor(conversion::mouse_interaction(interaction));
|
||||||
|
|
||||||
|
self.mouse_interaction = interaction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn draw_preedit(&mut self) {
|
pub fn draw_preedit(&mut self) {
|
||||||
if let Some(preedit) = &self.preedit {
|
if let Some(preedit) = &self.preedit {
|
||||||
preedit.draw(
|
preedit.draw(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue