Implement reactive-rendering for text_editor

This commit is contained in:
Héctor Ramón Jiménez 2024-11-04 23:21:06 +01:00
parent d5a886dbcb
commit 3482ffecdc
No known key found for this signature in database
GPG key ID: 4C07CEC81AFA161F

View file

@ -119,6 +119,7 @@ pub struct TextEditor<
&Highlighter::Highlight, &Highlighter::Highlight,
&Theme, &Theme,
) -> highlighter::Format<Renderer::Font>, ) -> highlighter::Format<Renderer::Font>,
last_status: Option<Status>,
} }
impl<'a, Message, Theme, Renderer> impl<'a, Message, Theme, Renderer>
@ -146,6 +147,7 @@ where
highlighter_format: |_highlight, _theme| { highlighter_format: |_highlight, _theme| {
highlighter::Format::default() highlighter::Format::default()
}, },
last_status: None,
} }
} }
} }
@ -269,6 +271,7 @@ where
on_edit: self.on_edit, on_edit: self.on_edit,
highlighter_settings: settings, highlighter_settings: settings,
highlighter_format: to_format, highlighter_format: to_format,
last_status: self.last_status,
} }
} }
@ -611,6 +614,10 @@ where
}; };
let state = tree.state.downcast_mut::<State<Highlighter>>(); let state = tree.state.downcast_mut::<State<Highlighter>>();
let is_redraw = matches!(
event,
Event::Window(window::Event::RedrawRequested(_now)),
);
match event { match event {
Event::Window(window::Event::Unfocused) => { Event::Window(window::Event::Unfocused) => {
@ -647,16 +654,15 @@ where
_ => {} _ => {}
} }
let Some(update) = Update::from_event( if let Some(update) = Update::from_event(
event, event,
state, state,
layout.bounds(), layout.bounds(),
self.padding, self.padding,
cursor, cursor,
self.key_binding.as_deref(), self.key_binding.as_deref(),
) else { ) {
return; shell.capture_event();
};
match update { match update {
Update::Click(click) => { Update::Click(click) => {
@ -707,7 +713,8 @@ where
clipboard: &mut dyn Clipboard, clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Message>,
) { ) {
let mut publish = |action| shell.publish(on_edit(action)); let mut publish =
|action| shell.publish(on_edit(action));
match binding { match binding {
Binding::Unfocus => { Binding::Unfocus => {
@ -736,9 +743,9 @@ where
if let Some(contents) = if let Some(contents) =
clipboard.read(clipboard::Kind::Standard) clipboard.read(clipboard::Kind::Standard)
{ {
publish(Action::Edit(Edit::Paste(Arc::new( publish(Action::Edit(Edit::Paste(
contents, Arc::new(contents),
)))); )));
} }
} }
Binding::Move(motion) => { Binding::Move(motion) => {
@ -796,8 +803,31 @@ where
} }
} }
} }
}
shell.capture_event(); let status = {
let is_disabled = self.on_edit.is_none();
let is_hovered = cursor.is_over(layout.bounds());
if is_disabled {
Status::Disabled
} else if state.focus.is_some() {
Status::Focused { is_hovered }
} else if is_hovered {
Status::Hovered
} else {
Status::Active
}
};
if is_redraw {
self.last_status = Some(status);
} else if self
.last_status
.is_some_and(|last_status| status != last_status)
{
shell.request_redraw();
}
} }
fn draw( fn draw(
@ -807,7 +837,7 @@ where
theme: &Theme, theme: &Theme,
_defaults: &renderer::Style, _defaults: &renderer::Style,
layout: Layout<'_>, layout: Layout<'_>,
cursor: mouse::Cursor, _cursor: mouse::Cursor,
_viewport: &Rectangle, _viewport: &Rectangle,
) { ) {
let bounds = layout.bounds(); let bounds = layout.bounds();
@ -823,20 +853,8 @@ where
|highlight| (self.highlighter_format)(highlight, theme), |highlight| (self.highlighter_format)(highlight, theme),
); );
let is_disabled = self.on_edit.is_none(); let style = theme
let is_mouse_over = cursor.is_over(bounds); .style(&self.class, self.last_status.unwrap_or(Status::Active));
let status = if is_disabled {
Status::Disabled
} else if state.focus.is_some() {
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 {
@ -1035,7 +1053,7 @@ impl<Message> Binding<Message> {
status, status,
} = event; } = event;
if status != Status::Focused { if !matches!(status, Status::Focused { .. }) {
return None; return None;
} }
@ -1175,7 +1193,9 @@ impl<Message> Update<Message> {
.. ..
}) => { }) => {
let status = if state.focus.is_some() { let status = if state.focus.is_some() {
Status::Focused Status::Focused {
is_hovered: cursor.is_over(bounds),
}
} else { } else {
Status::Active Status::Active
}; };
@ -1221,7 +1241,10 @@ pub enum Status {
/// The [`TextEditor`] is being hovered. /// The [`TextEditor`] is being hovered.
Hovered, Hovered,
/// The [`TextEditor`] is focused. /// The [`TextEditor`] is focused.
Focused, Focused {
/// Whether the [`TextEditor`] is hovered, while focused.
is_hovered: bool,
},
/// The [`TextEditor`] cannot be interacted with. /// The [`TextEditor`] cannot be interacted with.
Disabled, Disabled,
} }
@ -1296,7 +1319,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