Introduce Motion concept in core::text::editor

This commit is contained in:
Héctor Ramón Jiménez 2023-09-13 16:11:43 +02:00
parent 52b36a9574
commit f4c51a96d5
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
3 changed files with 157 additions and 66 deletions

View file

@ -40,14 +40,8 @@ pub trait Editor: Sized + Default {
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum Action { pub enum Action {
MoveLeft, Move(Motion),
MoveRight, Select(Motion),
MoveUp,
MoveDown,
MoveLeftWord,
MoveRightWord,
MoveHome,
MoveEnd,
SelectWord, SelectWord,
SelectLine, SelectLine,
Insert(char), Insert(char),
@ -58,6 +52,34 @@ pub enum Action {
Drag(Point), Drag(Point),
} }
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Motion {
Left,
Right,
Up,
Down,
WordLeft,
WordRight,
Home,
End,
PageUp,
PageDown,
DocumentStart,
DocumentEnd,
}
impl Motion {
pub fn widen(self) -> Self {
match self {
Self::Left => Self::WordLeft,
Self::Right => Self::WordRight,
Self::Home => Self::DocumentStart,
Self::End => Self::DocumentEnd,
_ => self,
}
}
}
/// The cursor of an [`Editor`]. /// The cursor of an [`Editor`].
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Cursor { pub enum Cursor {

View file

@ -1,4 +1,4 @@
use crate::core::text::editor::{self, Action, Cursor}; use crate::core::text::editor::{self, Action, Cursor, Motion};
use crate::core::text::LineHeight; use crate::core::text::LineHeight;
use crate::core::{Font, Pixels, Point, Rectangle, Size, Vector}; use crate::core::{Font, Pixels, Point, Rectangle, Size, Vector};
use crate::text; use crate::text;
@ -76,10 +76,7 @@ impl editor::Editor for Editor {
let buffer = internal.editor.buffer(); let buffer = internal.editor.buffer();
match internal.editor.select_opt() { match internal.editor.select_opt() {
Some(selection) Some(selection) => {
if cursor.line != selection.line
|| cursor.index != selection.index =>
{
let line_height = buffer.metrics().line_height; let line_height = buffer.metrics().line_height;
let scroll_offset = buffer.scroll() as f32 * line_height; let scroll_offset = buffer.scroll() as f32 * line_height;
@ -236,26 +233,87 @@ impl editor::Editor for Editor {
let editor = &mut internal.editor; let editor = &mut internal.editor;
let mut act = |action| editor.action(font_system.raw(), action);
match action { match action {
Action::MoveLeft => act(cosmic_text::Action::Left), // Motion events
Action::MoveRight => act(cosmic_text::Action::Right), Action::Move(motion) => {
Action::MoveUp => act(cosmic_text::Action::Up), if let Some(_selection) = editor.select_opt() {
Action::MoveDown => act(cosmic_text::Action::Down), editor.set_select_opt(None);
Action::Insert(c) => act(cosmic_text::Action::Insert(c)), } else {
Action::Enter => act(cosmic_text::Action::Enter), editor.action(
Action::Backspace => act(cosmic_text::Action::Backspace), font_system.raw(),
Action::Delete => act(cosmic_text::Action::Delete), match motion {
Action::Click(position) => act(cosmic_text::Action::Click { Motion::Left => cosmic_text::Action::Left,
x: position.x as i32, Motion::Right => cosmic_text::Action::Right,
y: position.y as i32, Motion::Up => cosmic_text::Action::Up,
}), Motion::Down => cosmic_text::Action::Down,
Action::Drag(position) => act(cosmic_text::Action::Drag { Motion::WordLeft => cosmic_text::Action::LeftWord,
x: position.x as i32, Motion::WordRight => cosmic_text::Action::RightWord,
y: position.y as i32, Motion::Home => cosmic_text::Action::Home,
}), Motion::End => cosmic_text::Action::End,
_ => todo!(), Motion::PageUp => cosmic_text::Action::PageUp,
Motion::PageDown => cosmic_text::Action::PageDown,
Motion::DocumentStart => {
cosmic_text::Action::BufferStart
}
Motion::DocumentEnd => {
cosmic_text::Action::BufferEnd
}
},
);
}
}
// Selection events
Action::Select(_motion) => todo!(),
Action::SelectWord => todo!(),
Action::SelectLine => todo!(),
// Editing events
Action::Insert(c) => {
editor
.action(font_system.raw(), cosmic_text::Action::Insert(c));
}
Action::Enter => {
editor.action(font_system.raw(), cosmic_text::Action::Enter);
}
Action::Backspace => {
editor
.action(font_system.raw(), cosmic_text::Action::Backspace);
}
Action::Delete => {
editor.action(font_system.raw(), cosmic_text::Action::Delete);
}
// Mouse events
Action::Click(position) => {
editor.action(
font_system.raw(),
cosmic_text::Action::Click {
x: position.x as i32,
y: position.y as i32,
},
);
}
Action::Drag(position) => {
editor.action(
font_system.raw(),
cosmic_text::Action::Drag {
x: position.x as i32,
y: position.y as i32,
},
);
// Deselect if selection matches cursor position
if let Some(selection) = editor.select_opt() {
let cursor = editor.cursor();
if cursor.line == selection.line
&& cursor.index == selection.index
{
editor.set_select_opt(None);
}
}
}
} }
editor.shape_as_needed(font_system.raw()); editor.shape_as_needed(font_system.raw());

View file

@ -14,7 +14,7 @@ use crate::core::{
use std::cell::RefCell; use std::cell::RefCell;
pub use crate::style::text_editor::{Appearance, StyleSheet}; pub use crate::style::text_editor::{Appearance, StyleSheet};
pub use text::editor::Action; pub use text::editor::{Action, Motion};
pub struct TextEditor<'a, Message, Renderer = crate::Renderer> pub struct TextEditor<'a, Message, Renderer = crate::Renderer>
where where
@ -189,16 +189,16 @@ where
}; };
match update { match update {
Update::Click { click, action } => {
state.is_focused = true;
state.is_dragging = true;
state.last_click = Some(click);
shell.publish(on_edit(action));
}
Update::Unfocus => { Update::Unfocus => {
state.is_focused = false; state.is_focused = false;
state.is_dragging = false; state.is_dragging = false;
} }
Update::Click { click, action } => {
state.is_focused = true;
state.last_click = Some(click);
state.is_dragging = true;
shell.publish(on_edit(action));
}
Update::StopDragging => { Update::StopDragging => {
state.is_dragging = false; state.is_dragging = false;
} }
@ -352,6 +352,9 @@ impl Update {
padding: Padding, padding: Padding,
cursor: mouse::Cursor, cursor: mouse::Cursor,
) -> Option<Self> { ) -> Option<Self> {
let edit = |action| Some(Update::Edit(action));
let move_ = |motion| Some(Update::Edit(Action::Move(motion)));
match event { match event {
Event::Mouse(event) => match event { Event::Mouse(event) => match event {
mouse::Event::ButtonPressed(mouse::Button::Left) => { mouse::Event::ButtonPressed(mouse::Button::Left) => {
@ -386,7 +389,7 @@ impl Update {
let cursor_position = cursor.position_in(bounds)? let cursor_position = cursor.position_in(bounds)?
- Vector::new(padding.top, padding.left); - Vector::new(padding.top, padding.left);
Some(Self::Edit(Action::Drag(cursor_position))) edit(Action::Drag(cursor_position))
} }
_ => None, _ => None,
}, },
@ -394,37 +397,31 @@ impl Update {
keyboard::Event::KeyPressed { keyboard::Event::KeyPressed {
key_code, key_code,
modifiers, modifiers,
} if state.is_focused => match key_code { } if state.is_focused => {
keyboard::KeyCode::Left => { if let Some(motion) = motion(key_code) {
if platform::is_jump_modifier_pressed(modifiers) { let motion = if modifiers.control() {
Some(Self::Edit(Action::MoveLeftWord)) motion.widen()
} else { } else {
Some(Self::Edit(Action::MoveLeft)) motion
} };
}
keyboard::KeyCode::Right => { return edit(if modifiers.shift() {
if platform::is_jump_modifier_pressed(modifiers) { Action::Select(motion)
Some(Self::Edit(Action::MoveRightWord))
} else { } else {
Some(Self::Edit(Action::MoveRight)) Action::Move(motion)
} });
} }
keyboard::KeyCode::Up => Some(Self::Edit(Action::MoveUp)),
keyboard::KeyCode::Down => { match key_code {
Some(Self::Edit(Action::MoveDown)) keyboard::KeyCode::Enter => edit(Action::Enter),
keyboard::KeyCode::Backspace => edit(Action::Backspace),
keyboard::KeyCode::Delete => edit(Action::Delete),
keyboard::KeyCode::Escape => Some(Self::Unfocus),
_ => None,
} }
keyboard::KeyCode::Enter => Some(Self::Edit(Action::Enter)), }
keyboard::KeyCode::Backspace => {
Some(Self::Edit(Action::Backspace))
}
keyboard::KeyCode::Delete => {
Some(Self::Edit(Action::Delete))
}
keyboard::KeyCode::Escape => Some(Self::Unfocus),
_ => None,
},
keyboard::Event::CharacterReceived(c) if state.is_focused => { keyboard::Event::CharacterReceived(c) if state.is_focused => {
Some(Self::Edit(Action::Insert(c))) edit(Action::Insert(c))
} }
_ => None, _ => None,
}, },
@ -433,6 +430,20 @@ impl Update {
} }
} }
fn motion(key_code: keyboard::KeyCode) -> Option<Motion> {
match key_code {
keyboard::KeyCode::Left => Some(Motion::Left),
keyboard::KeyCode::Right => Some(Motion::Right),
keyboard::KeyCode::Up => Some(Motion::Up),
keyboard::KeyCode::Down => Some(Motion::Down),
keyboard::KeyCode::Home => Some(Motion::Home),
keyboard::KeyCode::End => Some(Motion::End),
keyboard::KeyCode::PageUp => Some(Motion::PageUp),
keyboard::KeyCode::PageDown => Some(Motion::PageDown),
_ => None,
}
}
mod platform { mod platform {
use crate::core::keyboard; use crate::core::keyboard;