diff options
| -rw-r--r-- | core/src/text/editor.rs | 38 | ||||
| -rw-r--r-- | graphics/src/text/editor.rs | 106 | ||||
| -rw-r--r-- | widget/src/text_editor.rs | 77 | 
3 files changed, 156 insertions, 65 deletions
| diff --git a/core/src/text/editor.rs b/core/src/text/editor.rs index 09d4efde..f87e18f3 100644 --- a/core/src/text/editor.rs +++ b/core/src/text/editor.rs @@ -40,14 +40,8 @@ pub trait Editor: Sized + Default {  #[derive(Debug, Clone, Copy, PartialEq)]  pub enum Action { -    MoveLeft, -    MoveRight, -    MoveUp, -    MoveDown, -    MoveLeftWord, -    MoveRightWord, -    MoveHome, -    MoveEnd, +    Move(Motion), +    Select(Motion),      SelectWord,      SelectLine,      Insert(char), @@ -58,6 +52,34 @@ pub enum Action {      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`].  #[derive(Debug, Clone)]  pub enum Cursor { diff --git a/graphics/src/text/editor.rs b/graphics/src/text/editor.rs index 3544bde6..747f3a80 100644 --- a/graphics/src/text/editor.rs +++ b/graphics/src/text/editor.rs @@ -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::{Font, Pixels, Point, Rectangle, Size, Vector};  use crate::text; @@ -76,10 +76,7 @@ impl editor::Editor for Editor {          let buffer = internal.editor.buffer();          match internal.editor.select_opt() { -            Some(selection) -                if cursor.line != selection.line -                    || cursor.index != selection.index => -            { +            Some(selection) => {                  let line_height = buffer.metrics().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 mut act = |action| editor.action(font_system.raw(), action); -          match action { -            Action::MoveLeft => act(cosmic_text::Action::Left), -            Action::MoveRight => act(cosmic_text::Action::Right), -            Action::MoveUp => act(cosmic_text::Action::Up), -            Action::MoveDown => act(cosmic_text::Action::Down), -            Action::Insert(c) => act(cosmic_text::Action::Insert(c)), -            Action::Enter => act(cosmic_text::Action::Enter), -            Action::Backspace => act(cosmic_text::Action::Backspace), -            Action::Delete => act(cosmic_text::Action::Delete), -            Action::Click(position) => act(cosmic_text::Action::Click { -                x: position.x as i32, -                y: position.y as i32, -            }), -            Action::Drag(position) => act(cosmic_text::Action::Drag { -                x: position.x as i32, -                y: position.y as i32, -            }), -            _ => todo!(), +            // Motion events +            Action::Move(motion) => { +                if let Some(_selection) = editor.select_opt() { +                    editor.set_select_opt(None); +                } else { +                    editor.action( +                        font_system.raw(), +                        match motion { +                            Motion::Left => cosmic_text::Action::Left, +                            Motion::Right => cosmic_text::Action::Right, +                            Motion::Up => cosmic_text::Action::Up, +                            Motion::Down => cosmic_text::Action::Down, +                            Motion::WordLeft => cosmic_text::Action::LeftWord, +                            Motion::WordRight => cosmic_text::Action::RightWord, +                            Motion::Home => cosmic_text::Action::Home, +                            Motion::End => cosmic_text::Action::End, +                            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()); diff --git a/widget/src/text_editor.rs b/widget/src/text_editor.rs index a8069069..38c243bd 100644 --- a/widget/src/text_editor.rs +++ b/widget/src/text_editor.rs @@ -14,7 +14,7 @@ use crate::core::{  use std::cell::RefCell;  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>  where @@ -189,16 +189,16 @@ where          };          match update { -            Update::Unfocus => { -                state.is_focused = false; -                state.is_dragging = false; -            }              Update::Click { click, action } => {                  state.is_focused = true; -                state.last_click = Some(click);                  state.is_dragging = true; +                state.last_click = Some(click);                  shell.publish(on_edit(action));              } +            Update::Unfocus => { +                state.is_focused = false; +                state.is_dragging = false; +            }              Update::StopDragging => {                  state.is_dragging = false;              } @@ -352,6 +352,9 @@ impl Update {          padding: Padding,          cursor: mouse::Cursor,      ) -> Option<Self> { +        let edit = |action| Some(Update::Edit(action)); +        let move_ = |motion| Some(Update::Edit(Action::Move(motion))); +          match event {              Event::Mouse(event) => match event {                  mouse::Event::ButtonPressed(mouse::Button::Left) => { @@ -386,7 +389,7 @@ impl Update {                      let cursor_position = cursor.position_in(bounds)?                          - Vector::new(padding.top, padding.left); -                    Some(Self::Edit(Action::Drag(cursor_position))) +                    edit(Action::Drag(cursor_position))                  }                  _ => None,              }, @@ -394,37 +397,31 @@ impl Update {                  keyboard::Event::KeyPressed {                      key_code,                      modifiers, -                } if state.is_focused => match key_code { -                    keyboard::KeyCode::Left => { -                        if platform::is_jump_modifier_pressed(modifiers) { -                            Some(Self::Edit(Action::MoveLeftWord)) +                } if state.is_focused => { +                    if let Some(motion) = motion(key_code) { +                        let motion = if modifiers.control() { +                            motion.widen()                          } else { -                            Some(Self::Edit(Action::MoveLeft)) -                        } -                    } -                    keyboard::KeyCode::Right => { -                        if platform::is_jump_modifier_pressed(modifiers) { -                            Some(Self::Edit(Action::MoveRightWord)) +                            motion +                        }; + +                        return edit(if modifiers.shift() { +                            Action::Select(motion)                          } else { -                            Some(Self::Edit(Action::MoveRight)) -                        } -                    } -                    keyboard::KeyCode::Up => Some(Self::Edit(Action::MoveUp)), -                    keyboard::KeyCode::Down => { -                        Some(Self::Edit(Action::MoveDown)) -                    } -                    keyboard::KeyCode::Enter => Some(Self::Edit(Action::Enter)), -                    keyboard::KeyCode::Backspace => { -                        Some(Self::Edit(Action::Backspace)) +                            Action::Move(motion) +                        });                      } -                    keyboard::KeyCode::Delete => { -                        Some(Self::Edit(Action::Delete)) + +                    match key_code { +                        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::Escape => Some(Self::Unfocus), -                    _ => None, -                }, +                }                  keyboard::Event::CharacterReceived(c) if state.is_focused => { -                    Some(Self::Edit(Action::Insert(c))) +                    edit(Action::Insert(c))                  }                  _ => 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 {      use crate::core::keyboard; | 
