Implement reactive-rendering for text_input
... and fix the redraw queue logic in `iced_winit`.
This commit is contained in:
parent
3ba7c71e3f
commit
52490397d6
4 changed files with 201 additions and 88 deletions
|
|
@ -120,6 +120,7 @@ pub struct TextInput<
|
||||||
on_submit: Option<Message>,
|
on_submit: Option<Message>,
|
||||||
icon: Option<Icon<Renderer::Font>>,
|
icon: Option<Icon<Renderer::Font>>,
|
||||||
class: Theme::Class<'a>,
|
class: Theme::Class<'a>,
|
||||||
|
last_status: Option<Status>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The default [`Padding`] of a [`TextInput`].
|
/// The default [`Padding`] of a [`TextInput`].
|
||||||
|
|
@ -150,6 +151,7 @@ where
|
||||||
on_submit: None,
|
on_submit: None,
|
||||||
icon: None,
|
icon: None,
|
||||||
class: Theme::default(),
|
class: Theme::default(),
|
||||||
|
last_status: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -400,7 +402,7 @@ where
|
||||||
renderer: &mut Renderer,
|
renderer: &mut Renderer,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
layout: Layout<'_>,
|
layout: Layout<'_>,
|
||||||
cursor: mouse::Cursor,
|
_cursor: mouse::Cursor,
|
||||||
value: Option<&Value>,
|
value: Option<&Value>,
|
||||||
viewport: &Rectangle,
|
viewport: &Rectangle,
|
||||||
) {
|
) {
|
||||||
|
|
@ -416,19 +418,8 @@ where
|
||||||
let mut children_layout = layout.children();
|
let mut children_layout = layout.children();
|
||||||
let text_bounds = children_layout.next().unwrap().bounds();
|
let text_bounds = children_layout.next().unwrap().bounds();
|
||||||
|
|
||||||
let is_mouse_over = cursor.is_over(bounds);
|
let style = theme
|
||||||
|
.style(&self.class, self.last_status.unwrap_or(Status::Disabled));
|
||||||
let status = if is_disabled {
|
|
||||||
Status::Disabled
|
|
||||||
} else if state.is_focused() {
|
|
||||||
Status::Focused
|
|
||||||
} else if is_mouse_over {
|
|
||||||
Status::Hovered
|
|
||||||
} else {
|
|
||||||
Status::Active
|
|
||||||
};
|
|
||||||
|
|
||||||
let style = theme.style(&self.class, status);
|
|
||||||
|
|
||||||
renderer.fill_quad(
|
renderer.fill_quad(
|
||||||
renderer::Quad {
|
renderer::Quad {
|
||||||
|
|
@ -660,22 +651,21 @@ 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 { .. }) => {
|
||||||
let state = state::<Renderer>(tree);
|
let state = state::<Renderer>(tree);
|
||||||
|
let cursor_before = state.cursor;
|
||||||
|
|
||||||
let click_position = cursor.position_over(layout.bounds());
|
let click_position = cursor.position_over(layout.bounds());
|
||||||
|
|
||||||
state.is_focused = if click_position.is_some() {
|
state.is_focused = if click_position.is_some() {
|
||||||
state.is_focused.or_else(|| {
|
let now = Instant::now();
|
||||||
let now = Instant::now();
|
|
||||||
|
|
||||||
Some(Focus {
|
Some(Focus {
|
||||||
updated_at: now,
|
updated_at: now,
|
||||||
now,
|
now,
|
||||||
is_window_focused: true,
|
is_window_focused: true,
|
||||||
})
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -760,6 +750,10 @@ where
|
||||||
|
|
||||||
state.last_click = Some(click);
|
state.last_click = Some(click);
|
||||||
|
|
||||||
|
if cursor_before != state.cursor {
|
||||||
|
shell.request_redraw(window::RedrawRequest::NextFrame);
|
||||||
|
}
|
||||||
|
|
||||||
return event::Status::Captured;
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -801,10 +795,20 @@ where
|
||||||
)
|
)
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
|
|
||||||
|
let selection_before = state.cursor.selection(&value);
|
||||||
|
|
||||||
state
|
state
|
||||||
.cursor
|
.cursor
|
||||||
.select_range(state.cursor.start(&value), position);
|
.select_range(state.cursor.start(&value), position);
|
||||||
|
|
||||||
|
if let Some(focus) = &mut state.is_focused {
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
if selection_before != state.cursor.selection(&value) {
|
||||||
|
shell.request_redraw(window::RedrawRequest::NextFrame);
|
||||||
|
}
|
||||||
|
|
||||||
return event::Status::Captured;
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -815,7 +819,6 @@ where
|
||||||
|
|
||||||
if let Some(focus) = &mut state.is_focused {
|
if let Some(focus) = &mut state.is_focused {
|
||||||
let modifiers = state.keyboard_modifiers;
|
let modifiers = state.keyboard_modifiers;
|
||||||
focus.updated_at = Instant::now();
|
|
||||||
|
|
||||||
match key.as_ref() {
|
match key.as_ref() {
|
||||||
keyboard::Key::Character("c")
|
keyboard::Key::Character("c")
|
||||||
|
|
@ -857,6 +860,7 @@ where
|
||||||
let message = (on_input)(editor.contents());
|
let message = (on_input)(editor.contents());
|
||||||
shell.publish(message);
|
shell.publish(message);
|
||||||
|
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
update_cache(state, &self.value);
|
update_cache(state, &self.value);
|
||||||
|
|
||||||
return event::Status::Captured;
|
return event::Status::Captured;
|
||||||
|
|
@ -885,7 +889,6 @@ where
|
||||||
|
|
||||||
let mut editor =
|
let mut editor =
|
||||||
Editor::new(&mut self.value, &mut state.cursor);
|
Editor::new(&mut self.value, &mut state.cursor);
|
||||||
|
|
||||||
editor.paste(content.clone());
|
editor.paste(content.clone());
|
||||||
|
|
||||||
let message = if let Some(paste) = &self.on_paste {
|
let message = if let Some(paste) = &self.on_paste {
|
||||||
|
|
@ -896,7 +899,7 @@ where
|
||||||
shell.publish(message);
|
shell.publish(message);
|
||||||
|
|
||||||
state.is_pasting = Some(content);
|
state.is_pasting = Some(content);
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
update_cache(state, &self.value);
|
update_cache(state, &self.value);
|
||||||
|
|
||||||
return event::Status::Captured;
|
return event::Status::Captured;
|
||||||
|
|
@ -904,8 +907,18 @@ where
|
||||||
keyboard::Key::Character("a")
|
keyboard::Key::Character("a")
|
||||||
if state.keyboard_modifiers.command() =>
|
if state.keyboard_modifiers.command() =>
|
||||||
{
|
{
|
||||||
|
let cursor_before = state.cursor;
|
||||||
|
|
||||||
state.cursor.select_all(&self.value);
|
state.cursor.select_all(&self.value);
|
||||||
|
|
||||||
|
if cursor_before != state.cursor {
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
|
|
||||||
|
shell.request_redraw(
|
||||||
|
window::RedrawRequest::NextFrame,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return event::Status::Captured;
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -930,7 +943,6 @@ where
|
||||||
shell.publish(message);
|
shell.publish(message);
|
||||||
|
|
||||||
focus.updated_at = Instant::now();
|
focus.updated_at = Instant::now();
|
||||||
|
|
||||||
update_cache(state, &self.value);
|
update_cache(state, &self.value);
|
||||||
|
|
||||||
return event::Status::Captured;
|
return event::Status::Captured;
|
||||||
|
|
@ -941,6 +953,8 @@ where
|
||||||
keyboard::Key::Named(key::Named::Enter) => {
|
keyboard::Key::Named(key::Named::Enter) => {
|
||||||
if let Some(on_submit) = self.on_submit.clone() {
|
if let Some(on_submit) = self.on_submit.clone() {
|
||||||
shell.publish(on_submit);
|
shell.publish(on_submit);
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyboard::Key::Named(key::Named::Backspace) => {
|
keyboard::Key::Named(key::Named::Backspace) => {
|
||||||
|
|
@ -969,7 +983,10 @@ where
|
||||||
let message = (on_input)(editor.contents());
|
let message = (on_input)(editor.contents());
|
||||||
shell.publish(message);
|
shell.publish(message);
|
||||||
|
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
update_cache(state, &self.value);
|
update_cache(state, &self.value);
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
keyboard::Key::Named(key::Named::Delete) => {
|
keyboard::Key::Named(key::Named::Delete) => {
|
||||||
let Some(on_input) = &self.on_input else {
|
let Some(on_input) = &self.on_input else {
|
||||||
|
|
@ -1000,9 +1017,14 @@ where
|
||||||
let message = (on_input)(editor.contents());
|
let message = (on_input)(editor.contents());
|
||||||
shell.publish(message);
|
shell.publish(message);
|
||||||
|
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
update_cache(state, &self.value);
|
update_cache(state, &self.value);
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
keyboard::Key::Named(key::Named::Home) => {
|
keyboard::Key::Named(key::Named::Home) => {
|
||||||
|
let cursor_before = state.cursor;
|
||||||
|
|
||||||
if modifiers.shift() {
|
if modifiers.shift() {
|
||||||
state.cursor.select_range(
|
state.cursor.select_range(
|
||||||
state.cursor.start(&self.value),
|
state.cursor.start(&self.value),
|
||||||
|
|
@ -1011,8 +1033,20 @@ where
|
||||||
} else {
|
} else {
|
||||||
state.cursor.move_to(0);
|
state.cursor.move_to(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cursor_before != state.cursor {
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
|
|
||||||
|
shell.request_redraw(
|
||||||
|
window::RedrawRequest::NextFrame,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
keyboard::Key::Named(key::Named::End) => {
|
keyboard::Key::Named(key::Named::End) => {
|
||||||
|
let cursor_before = state.cursor;
|
||||||
|
|
||||||
if modifiers.shift() {
|
if modifiers.shift() {
|
||||||
state.cursor.select_range(
|
state.cursor.select_range(
|
||||||
state.cursor.start(&self.value),
|
state.cursor.start(&self.value),
|
||||||
|
|
@ -1021,10 +1055,22 @@ where
|
||||||
} else {
|
} else {
|
||||||
state.cursor.move_to(self.value.len());
|
state.cursor.move_to(self.value.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cursor_before != state.cursor {
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
|
|
||||||
|
shell.request_redraw(
|
||||||
|
window::RedrawRequest::NextFrame,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
keyboard::Key::Named(key::Named::ArrowLeft)
|
keyboard::Key::Named(key::Named::ArrowLeft)
|
||||||
if modifiers.macos_command() =>
|
if modifiers.macos_command() =>
|
||||||
{
|
{
|
||||||
|
let cursor_before = state.cursor;
|
||||||
|
|
||||||
if modifiers.shift() {
|
if modifiers.shift() {
|
||||||
state.cursor.select_range(
|
state.cursor.select_range(
|
||||||
state.cursor.start(&self.value),
|
state.cursor.start(&self.value),
|
||||||
|
|
@ -1033,10 +1079,22 @@ where
|
||||||
} else {
|
} else {
|
||||||
state.cursor.move_to(0);
|
state.cursor.move_to(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cursor_before != state.cursor {
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
|
|
||||||
|
shell.request_redraw(
|
||||||
|
window::RedrawRequest::NextFrame,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
keyboard::Key::Named(key::Named::ArrowRight)
|
keyboard::Key::Named(key::Named::ArrowRight)
|
||||||
if modifiers.macos_command() =>
|
if modifiers.macos_command() =>
|
||||||
{
|
{
|
||||||
|
let cursor_before = state.cursor;
|
||||||
|
|
||||||
if modifiers.shift() {
|
if modifiers.shift() {
|
||||||
state.cursor.select_range(
|
state.cursor.select_range(
|
||||||
state.cursor.start(&self.value),
|
state.cursor.start(&self.value),
|
||||||
|
|
@ -1045,8 +1103,20 @@ where
|
||||||
} else {
|
} else {
|
||||||
state.cursor.move_to(self.value.len());
|
state.cursor.move_to(self.value.len());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cursor_before != state.cursor {
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
|
|
||||||
|
shell.request_redraw(
|
||||||
|
window::RedrawRequest::NextFrame,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
keyboard::Key::Named(key::Named::ArrowLeft) => {
|
keyboard::Key::Named(key::Named::ArrowLeft) => {
|
||||||
|
let cursor_before = state.cursor;
|
||||||
|
|
||||||
if modifiers.jump() && !self.is_secure {
|
if modifiers.jump() && !self.is_secure {
|
||||||
if modifiers.shift() {
|
if modifiers.shift() {
|
||||||
state
|
state
|
||||||
|
|
@ -1062,8 +1132,20 @@ where
|
||||||
} else {
|
} else {
|
||||||
state.cursor.move_left(&self.value);
|
state.cursor.move_left(&self.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cursor_before != state.cursor {
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
|
|
||||||
|
shell.request_redraw(
|
||||||
|
window::RedrawRequest::NextFrame,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
keyboard::Key::Named(key::Named::ArrowRight) => {
|
keyboard::Key::Named(key::Named::ArrowRight) => {
|
||||||
|
let cursor_before = state.cursor;
|
||||||
|
|
||||||
if modifiers.jump() && !self.is_secure {
|
if modifiers.jump() && !self.is_secure {
|
||||||
if modifiers.shift() {
|
if modifiers.shift() {
|
||||||
state
|
state
|
||||||
|
|
@ -1079,6 +1161,16 @@ where
|
||||||
} else {
|
} else {
|
||||||
state.cursor.move_right(&self.value);
|
state.cursor.move_right(&self.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cursor_before != state.cursor {
|
||||||
|
focus.updated_at = Instant::now();
|
||||||
|
|
||||||
|
shell.request_redraw(
|
||||||
|
window::RedrawRequest::NextFrame,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return event::Status::Captured;
|
||||||
}
|
}
|
||||||
keyboard::Key::Named(key::Named::Escape) => {
|
keyboard::Key::Named(key::Named::Escape) => {
|
||||||
state.is_focused = None;
|
state.is_focused = None;
|
||||||
|
|
@ -1087,39 +1179,22 @@ where
|
||||||
|
|
||||||
state.keyboard_modifiers =
|
state.keyboard_modifiers =
|
||||||
keyboard::Modifiers::default();
|
keyboard::Modifiers::default();
|
||||||
}
|
|
||||||
keyboard::Key::Named(
|
return event::Status::Captured;
|
||||||
key::Named::Tab
|
|
||||||
| key::Named::ArrowUp
|
|
||||||
| key::Named::ArrowDown,
|
|
||||||
) => {
|
|
||||||
return event::Status::Ignored;
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
return event::Status::Captured;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Keyboard(keyboard::Event::KeyReleased { key, .. }) => {
|
Event::Keyboard(keyboard::Event::KeyReleased { key, .. }) => {
|
||||||
let state = state::<Renderer>(tree);
|
let state = state::<Renderer>(tree);
|
||||||
|
|
||||||
if state.is_focused.is_some() {
|
if state.is_focused.is_some() {
|
||||||
match key.as_ref() {
|
if let keyboard::Key::Character("v") = key.as_ref() {
|
||||||
keyboard::Key::Character("v") => {
|
state.is_pasting = None;
|
||||||
state.is_pasting = None;
|
|
||||||
}
|
|
||||||
keyboard::Key::Named(
|
|
||||||
key::Named::Tab
|
|
||||||
| key::Named::ArrowUp
|
|
||||||
| key::Named::ArrowDown,
|
|
||||||
) => {
|
|
||||||
return event::Status::Ignored;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
return event::Status::Captured;
|
return event::Status::Captured;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.is_pasting = None;
|
state.is_pasting = None;
|
||||||
|
|
@ -1127,7 +1202,7 @@ where
|
||||||
Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => {
|
Event::Keyboard(keyboard::Event::ModifiersChanged(modifiers)) => {
|
||||||
let state = state::<Renderer>(tree);
|
let state = state::<Renderer>(tree);
|
||||||
|
|
||||||
state.keyboard_modifiers = modifiers;
|
state.keyboard_modifiers = *modifiers;
|
||||||
}
|
}
|
||||||
Event::Window(window::Event::Unfocused) => {
|
Event::Window(window::Event::Unfocused) => {
|
||||||
let state = state::<Renderer>(tree);
|
let state = state::<Renderer>(tree);
|
||||||
|
|
@ -1150,15 +1225,20 @@ where
|
||||||
let state = state::<Renderer>(tree);
|
let state = state::<Renderer>(tree);
|
||||||
|
|
||||||
if let Some(focus) = &mut state.is_focused {
|
if let Some(focus) = &mut state.is_focused {
|
||||||
if focus.is_window_focused {
|
if focus.is_window_focused
|
||||||
focus.now = now;
|
&& matches!(
|
||||||
|
state.cursor.state(&self.value),
|
||||||
|
cursor::State::Index(_)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
focus.now = *now;
|
||||||
|
|
||||||
let millis_until_redraw = CURSOR_BLINK_INTERVAL_MILLIS
|
let millis_until_redraw = CURSOR_BLINK_INTERVAL_MILLIS
|
||||||
- (now - focus.updated_at).as_millis()
|
- (*now - focus.updated_at).as_millis()
|
||||||
% CURSOR_BLINK_INTERVAL_MILLIS;
|
% CURSOR_BLINK_INTERVAL_MILLIS;
|
||||||
|
|
||||||
shell.request_redraw(window::RedrawRequest::At(
|
shell.request_redraw(window::RedrawRequest::At(
|
||||||
now + Duration::from_millis(
|
*now + Duration::from_millis(
|
||||||
millis_until_redraw as u64,
|
millis_until_redraw as u64,
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
|
|
@ -1168,6 +1248,32 @@ where
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let state = state::<Renderer>(tree);
|
||||||
|
let is_disabled = self.on_input.is_none();
|
||||||
|
|
||||||
|
let status = if is_disabled {
|
||||||
|
Status::Disabled
|
||||||
|
} else if state.is_focused() {
|
||||||
|
Status::Focused {
|
||||||
|
is_hovered: cursor.is_over(layout.bounds()),
|
||||||
|
}
|
||||||
|
} else if cursor.is_over(layout.bounds()) {
|
||||||
|
Status::Hovered
|
||||||
|
} else {
|
||||||
|
Status::Active
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Event::Window(window::Event::RedrawRequested(_now)) = event {
|
||||||
|
self.last_status = Some(status);
|
||||||
|
} else {
|
||||||
|
match self.last_status {
|
||||||
|
Some(last_status) if status != last_status => {
|
||||||
|
shell.request_redraw(window::RedrawRequest::NextFrame);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
event::Status::Ignored
|
event::Status::Ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1535,7 +1641,10 @@ pub enum Status {
|
||||||
/// The [`TextInput`] is being hovered.
|
/// The [`TextInput`] is being hovered.
|
||||||
Hovered,
|
Hovered,
|
||||||
/// The [`TextInput`] is focused.
|
/// The [`TextInput`] is focused.
|
||||||
Focused,
|
Focused {
|
||||||
|
/// Whether the [`TextInput`] is hovered, while focused.
|
||||||
|
is_hovered: bool,
|
||||||
|
},
|
||||||
/// The [`TextInput`] cannot be interacted with.
|
/// The [`TextInput`] cannot be interacted with.
|
||||||
Disabled,
|
Disabled,
|
||||||
}
|
}
|
||||||
|
|
@ -1612,7 +1721,7 @@ pub fn default(theme: &Theme, status: Status) -> Style {
|
||||||
},
|
},
|
||||||
..active
|
..active
|
||||||
},
|
},
|
||||||
Status::Focused => Style {
|
Status::Focused { .. } => Style {
|
||||||
border: Border {
|
border: Border {
|
||||||
color: palette.primary.strong.color,
|
color: palette.primary.strong.color,
|
||||||
..active.border
|
..active.border
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@
|
||||||
use crate::text_input::Value;
|
use crate::text_input::Value;
|
||||||
|
|
||||||
/// The cursor of a text input.
|
/// The cursor of a text input.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct Cursor {
|
pub struct Cursor {
|
||||||
state: State,
|
state: State,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The state of a [`Cursor`].
|
/// The state of a [`Cursor`].
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum State {
|
pub enum State {
|
||||||
/// Cursor without a selection
|
/// Cursor without a selection
|
||||||
Index(usize),
|
Index(usize),
|
||||||
|
|
|
||||||
|
|
@ -691,7 +691,6 @@ async fn run_instance<P, C>(
|
||||||
let mut ui_caches = FxHashMap::default();
|
let mut ui_caches = FxHashMap::default();
|
||||||
let mut user_interfaces = ManuallyDrop::new(FxHashMap::default());
|
let mut user_interfaces = ManuallyDrop::new(FxHashMap::default());
|
||||||
let mut clipboard = Clipboard::unconnected();
|
let mut clipboard = Clipboard::unconnected();
|
||||||
let mut redraw_queue = Vec::new();
|
|
||||||
|
|
||||||
debug.startup_finished();
|
debug.startup_finished();
|
||||||
|
|
||||||
|
|
@ -769,17 +768,12 @@ async fn run_instance<P, C>(
|
||||||
) => {
|
) => {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
||||||
while let Some((target, id)) =
|
for (_id, window) in window_manager.iter_mut() {
|
||||||
redraw_queue.last().copied()
|
if let Some(redraw_at) = window.redraw_at {
|
||||||
{
|
if redraw_at <= now {
|
||||||
if target > now {
|
window.raw.request_redraw();
|
||||||
break;
|
window.redraw_at = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = redraw_queue.pop();
|
|
||||||
|
|
||||||
if let Some(window) = window_manager.get_mut(id) {
|
|
||||||
window.raw.request_redraw();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -878,7 +872,7 @@ async fn run_instance<P, C>(
|
||||||
window.raw.request_redraw();
|
window.raw.request_redraw();
|
||||||
}
|
}
|
||||||
window::RedrawRequest::At(at) => {
|
window::RedrawRequest::At(at) => {
|
||||||
redraw_queue.push((at, id));
|
window.redraw_at = Some(at);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1039,7 +1033,10 @@ async fn run_instance<P, C>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
event::Event::AboutToWait => {
|
event::Event::AboutToWait => {
|
||||||
if events.is_empty() && messages.is_empty() {
|
if events.is_empty()
|
||||||
|
&& messages.is_empty()
|
||||||
|
&& window_manager.is_idle()
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1085,7 +1082,7 @@ async fn run_instance<P, C>(
|
||||||
window.raw.request_redraw();
|
window.raw.request_redraw();
|
||||||
}
|
}
|
||||||
window::RedrawRequest::At(at) => {
|
window::RedrawRequest::At(at) => {
|
||||||
redraw_queue.push((at, id));
|
window.redraw_at = Some(at);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
user_interface::State::Outdated => {
|
user_interface::State::Outdated => {
|
||||||
|
|
@ -1160,24 +1157,15 @@ async fn run_instance<P, C>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !redraw_queue.is_empty() {
|
if let Some(redraw_at) = window_manager.redraw_at() {
|
||||||
// The queue should be fairly short, so we can
|
|
||||||
// simply sort all of the time.
|
|
||||||
redraw_queue.sort_by(
|
|
||||||
|(target_a, _), (target_b, _)| {
|
|
||||||
target_a.cmp(target_b).reverse()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
let (target, _id) = redraw_queue
|
|
||||||
.last()
|
|
||||||
.copied()
|
|
||||||
.expect("Redraw queue is not empty");
|
|
||||||
|
|
||||||
let _ =
|
let _ =
|
||||||
control_sender.start_send(Control::ChangeFlow(
|
control_sender.start_send(Control::ChangeFlow(
|
||||||
ControlFlow::WaitUntil(target),
|
ControlFlow::WaitUntil(redraw_at),
|
||||||
));
|
));
|
||||||
|
} else {
|
||||||
|
let _ = control_sender.start_send(
|
||||||
|
Control::ChangeFlow(ControlFlow::Wait),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use crate::core::mouse;
|
use crate::core::mouse;
|
||||||
|
use crate::core::time::Instant;
|
||||||
use crate::core::window::Id;
|
use crate::core::window::Id;
|
||||||
use crate::core::{Point, Size};
|
use crate::core::{Point, Size};
|
||||||
use crate::graphics::Compositor;
|
use crate::graphics::Compositor;
|
||||||
|
|
@ -62,6 +63,7 @@ where
|
||||||
surface,
|
surface,
|
||||||
renderer,
|
renderer,
|
||||||
mouse_interaction: mouse::Interaction::None,
|
mouse_interaction: mouse::Interaction::None,
|
||||||
|
redraw_at: None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -74,6 +76,19 @@ where
|
||||||
self.entries.is_empty()
|
self.entries.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_idle(&self) -> bool {
|
||||||
|
self.entries
|
||||||
|
.values()
|
||||||
|
.any(|window| window.redraw_at.is_some())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn redraw_at(&self) -> Option<Instant> {
|
||||||
|
self.entries
|
||||||
|
.values()
|
||||||
|
.filter_map(|window| window.redraw_at)
|
||||||
|
.min()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn first(&self) -> Option<&Window<P, C>> {
|
pub fn first(&self) -> Option<&Window<P, C>> {
|
||||||
self.entries.first_key_value().map(|(_id, window)| window)
|
self.entries.first_key_value().map(|(_id, window)| window)
|
||||||
}
|
}
|
||||||
|
|
@ -138,6 +153,7 @@ where
|
||||||
pub mouse_interaction: mouse::Interaction,
|
pub mouse_interaction: mouse::Interaction,
|
||||||
pub surface: C::Surface,
|
pub surface: C::Surface,
|
||||||
pub renderer: P::Renderer,
|
pub renderer: P::Renderer,
|
||||||
|
pub redraw_at: Option<Instant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P, C> Window<P, C>
|
impl<P, C> Window<P, C>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue