summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--native/src/lib.rs2
-rw-r--r--native/src/widget/text_input.rs78
-rw-r--r--native/src/widget/text_input/cursor.rs98
-rw-r--r--wgpu/src/renderer/widget/text_input.rs121
4 files changed, 164 insertions, 135 deletions
diff --git a/native/src/lib.rs b/native/src/lib.rs
index d17dd918..5c6ab3ee 100644
--- a/native/src/lib.rs
+++ b/native/src/lib.rs
@@ -34,7 +34,7 @@
//! [`window::Renderer`]: window/trait.Renderer.html
//! [`UserInterface`]: struct.UserInterface.html
//! [renderer]: renderer/index.html
-#![deny(missing_docs)]
+//#![deny(missing_docs)]
#![deny(missing_debug_implementations)]
#![deny(unused_results)]
#![forbid(unsafe_code)]
diff --git a/native/src/widget/text_input.rs b/native/src/widget/text_input.rs
index c379f0d1..f5ca16e1 100644
--- a/native/src/widget/text_input.rs
+++ b/native/src/widget/text_input.rs
@@ -4,17 +4,18 @@
//!
//! [`TextInput`]: struct.TextInput.html
//! [`State`]: struct.State.html
-mod cursor;
+pub mod cursor;
+
+pub use cursor::Cursor;
+
use crate::{
input::{
keyboard,
mouse::{self, click},
ButtonState,
},
- layout,
- widget::text_input::cursor::Cursor,
- Clipboard, Element, Event, Font, Hasher, Layout, Length, Point, Rectangle,
- Size, Widget,
+ layout, Clipboard, Element, Event, Font, Hasher, Layout, Length, Point,
+ Rectangle, Size, Widget,
};
use std::u32;
@@ -261,7 +262,8 @@ where
if self.is_secure {
self.state.cursor.select_all(&self.value);
} else {
- let end = self.state.cursor.end();
+ let end = self.state.cursor.end(&self.value);
+
self.state.cursor.select_range(
self.value.previous_start_of_word(end),
self.value.next_end_of_word(end),
@@ -307,7 +309,7 @@ where
self.font,
);
- let pos = find_cursor_position(
+ let position = find_cursor_position(
renderer,
target + offset,
&value,
@@ -317,9 +319,10 @@ where
self.font,
);
- self.state
- .cursor
- .select_range(self.state.cursor.start(), pos);
+ self.state.cursor.select_range(
+ self.state.cursor.start(&value),
+ position,
+ );
}
}
}
@@ -328,15 +331,15 @@ where
&& self.state.is_pasting.is_none()
&& !c.is_control() =>
{
- match self.state.cursor.selection_position() {
+ match self.state.cursor.selection() {
Some((left, right)) => {
self.value.remove_many(left, right);
- self.state.cursor.move_left();
+ self.state.cursor.move_left(&self.value);
}
_ => (),
}
- self.value
- .insert(self.state.cursor.end().min(self.value.len()), c);
+
+ self.value.insert(self.state.cursor.end(&self.value), c);
self.state.cursor.move_right(&self.value);
let message = (self.on_change)(self.value.to_string());
@@ -353,19 +356,18 @@ where
}
}
keyboard::KeyCode::Backspace => {
- match self.state.cursor.selection_position() {
+ match self.state.cursor.selection() {
Some((start, end)) => {
self.value.remove_many(start, end);
- self.state.cursor.move_left();
+ self.state.cursor.move_left(&self.value);
}
None => {
- if self.state.cursor.start().min(self.value.len())
- > 0
- {
- self.state.cursor.move_left();
- let _ = self
- .value
- .remove(self.state.cursor.start());
+ if self.state.cursor.start(&self.value) > 0 {
+ self.state.cursor.move_left(&self.value);
+
+ let _ = self.value.remove(
+ self.state.cursor.start(&self.value),
+ );
}
}
}
@@ -373,15 +375,16 @@ where
messages.push(message);
}
keyboard::KeyCode::Delete => {
- match self.state.cursor.selection_position() {
+ match self.state.cursor.selection() {
Some((start, end)) => {
self.value.remove_many(start, end);
- self.state.cursor.move_left();
+ self.state.cursor.move_left(&self.value);
}
None => {
- if self.state.cursor.end() < self.value.len() {
- let _ =
- self.value.remove(self.state.cursor.end());
+ let end = self.state.cursor.end(&self.value);
+
+ if end > 0 {
+ let _ = self.value.remove(end);
}
}
}
@@ -398,9 +401,9 @@ where
self.state.cursor.move_left_by_words(&self.value);
}
} else if modifiers.shift {
- self.state.cursor.select_left()
+ self.state.cursor.select_left(&self.value)
} else {
- self.state.cursor.move_left();
+ self.state.cursor.move_left(&self.value);
}
}
keyboard::KeyCode::Right => {
@@ -422,9 +425,10 @@ where
}
keyboard::KeyCode::Home => {
if modifiers.shift {
- self.state
- .cursor
- .select_range(self.state.cursor.start(), 0);
+ self.state.cursor.select_range(
+ self.state.cursor.start(&self.value),
+ 0,
+ );
} else {
self.state.cursor.move_to(0);
}
@@ -432,7 +436,7 @@ where
keyboard::KeyCode::End => {
if modifiers.shift {
self.state.cursor.select_range(
- self.state.cursor.start(),
+ self.state.cursor.start(&self.value),
self.value.len(),
);
} else {
@@ -456,16 +460,16 @@ where
}
};
- match self.state.cursor.selection_position() {
+ match self.state.cursor.selection() {
Some((left, right)) => {
self.value.remove_many(left, right);
- self.state.cursor.move_left();
+ self.state.cursor.move_left(&self.value);
}
_ => (),
}
self.value.insert_many(
- self.state.cursor.end().min(self.value.len()),
+ self.state.cursor.end(&self.value),
content.clone(),
);
diff --git a/native/src/widget/text_input/cursor.rs b/native/src/widget/text_input/cursor.rs
index 92fd2029..d8938777 100644
--- a/native/src/widget/text_input/cursor.rs
+++ b/native/src/widget/text_input/cursor.rs
@@ -1,7 +1,8 @@
+//! Track the cursor of a text input.
use crate::widget::text_input::Value;
#[derive(Debug, Copy, Clone)]
-enum State {
+pub enum State {
Index(usize),
Selection { start: usize, end: usize },
}
@@ -20,7 +21,6 @@ impl Default for Cursor {
}
impl Cursor {
- /* index move methods */
pub fn move_to(&mut self, position: usize) {
self.state = State::Index(position);
}
@@ -30,42 +30,40 @@ impl Cursor {
}
pub fn move_right_by_words(&mut self, value: &Value) {
- self.move_to(value.next_end_of_word(self.right()))
+ self.move_to(value.next_end_of_word(self.right(value)))
}
pub fn move_right_by_amount(&mut self, value: &Value, amount: usize) {
- match self.state {
+ match self.state(value) {
State::Index(index) => {
self.move_to(index.saturating_add(amount).min(value.len()))
}
- State::Selection { .. } => self.move_to(self.right()),
+ State::Selection { start, end } => self.move_to(end.max(start)),
}
}
- pub fn move_left(&mut self) {
- match self.state {
+ pub fn move_left(&mut self, value: &Value) {
+ match self.state(value) {
State::Index(index) if index > 0 => self.move_to(index - 1),
- State::Selection { .. } => self.move_to(self.left()),
+ State::Selection { start, end } => self.move_to(start.min(end)),
_ => self.move_to(0),
}
}
pub fn move_left_by_words(&mut self, value: &Value) {
- self.move_to(value.previous_start_of_word(self.right()));
+ self.move_to(value.previous_start_of_word(self.left(value)));
}
- /* end of index move methods */
- /* expand/shrink selection */
pub fn select_range(&mut self, start: usize, end: usize) {
- if start != end {
- self.state = State::Selection { start, end };
- } else {
+ if start == end {
self.state = State::Index(start);
+ } else {
+ self.state = State::Selection { start, end };
}
}
- pub fn select_left(&mut self) {
- match self.state {
+ pub fn select_left(&mut self, value: &Value) {
+ match self.state(value) {
State::Index(index) if index > 0 => {
self.select_range(index, index - 1)
}
@@ -77,7 +75,7 @@ impl Cursor {
}
pub fn select_right(&mut self, value: &Value) {
- match self.state {
+ match self.state(value) {
State::Index(index) if index < value.len() => {
self.select_range(index, index + 1)
}
@@ -89,7 +87,7 @@ impl Cursor {
}
pub fn select_left_by_words(&mut self, value: &Value) {
- match self.state {
+ match self.state(value) {
State::Index(index) => {
self.select_range(index, value.previous_start_of_word(index))
}
@@ -100,7 +98,7 @@ impl Cursor {
}
pub fn select_right_by_words(&mut self, value: &Value) {
- match self.state {
+ match self.state(value) {
State::Index(index) => {
self.select_range(index, value.next_end_of_word(index))
}
@@ -113,51 +111,56 @@ impl Cursor {
pub fn select_all(&mut self, value: &Value) {
self.select_range(0, value.len());
}
- /* end of selection section */
- /* helpers */
- // get start position of selection (can be left OR right boundary of selection) or index
- pub(crate) fn start(&self) -> usize {
+ pub fn state(&self, value: &Value) -> State {
match self.state {
+ State::Index(index) => State::Index(index.min(value.len())),
+ State::Selection { start, end } => {
+ let start = start.min(value.len());
+ let end = end.min(value.len());
+
+ if start == end {
+ State::Index(start)
+ } else {
+ State::Selection { start, end }
+ }
+ }
+ }
+ }
+
+ pub fn start(&self, value: &Value) -> usize {
+ let start = match self.state {
State::Index(index) => index,
State::Selection { start, .. } => start,
- }
+ };
+
+ start.min(value.len())
}
- // get end position of selection (can be left OR right boundary of selection) or index
- pub fn end(&self) -> usize {
- match self.state {
+ pub fn end(&self, value: &Value) -> usize {
+ let end = match self.state {
State::Index(index) => index,
State::Selection { end, .. } => end,
- }
+ };
+
+ end.min(value.len())
}
- // get left boundary of selection or index
- pub fn left(&self) -> usize {
- match self.state {
+ fn left(&self, value: &Value) -> usize {
+ match self.state(value) {
State::Index(index) => index,
State::Selection { start, end } => start.min(end),
}
}
- // get right boundary of selection or index
- pub fn right(&self) -> usize {
- match self.state {
+ fn right(&self, value: &Value) -> usize {
+ match self.state(value) {
State::Index(index) => index,
State::Selection { start, end } => start.max(end),
}
}
- pub fn cursor_position(&self, value: &Value) -> usize {
- match self.state {
- State::Index(index) => index.min(value.len()),
- State::Selection { end, .. } => end.min(value.len()),
- }
- }
-
- // returns Option of left and right border of selection
- // a second method that returns start and end may be useful (see below)
- pub fn selection_position(&self) -> Option<(usize, usize)> {
+ pub fn selection(&self) -> Option<(usize, usize)> {
match self.state {
State::Selection { start, end } => {
Some((start.min(end), start.max(end)))
@@ -165,11 +168,4 @@ impl Cursor {
_ => None,
}
}
-
- /* pub fn selection_position(&self) -> Option<(usize, usize)> {
- match self.state {
- State::Selection { start, end } => Some((start, end)),
- _ => None,
- }
- } */
}
diff --git a/wgpu/src/renderer/widget/text_input.rs b/wgpu/src/renderer/widget/text_input.rs
index fa108d68..74f30be1 100644
--- a/wgpu/src/renderer/widget/text_input.rs
+++ b/wgpu/src/renderer/widget/text_input.rs
@@ -1,8 +1,9 @@
use crate::{text_input::StyleSheet, Primitive, Renderer};
use iced_native::{
- text_input, Background, Color, Font, HorizontalAlignment, MouseCursor,
- Point, Rectangle, Size, Vector, VerticalAlignment,
+ text_input::{self, cursor},
+ Background, Color, Font, HorizontalAlignment, MouseCursor, Point,
+ Rectangle, Size, Vector, VerticalAlignment,
};
use std::f32;
@@ -41,12 +42,19 @@ impl text_input::Renderer for Renderer {
font: Font,
) -> f32 {
if state.is_focused() {
+ let cursor = state.cursor();
+
+ let focus_position = match cursor.state(value) {
+ cursor::State::Index(i) => i,
+ cursor::State::Selection { end, .. } => end,
+ };
+
let (_, offset) = measure_cursor_and_scroll_offset(
self,
text_bounds,
value,
size,
- state.cursor().cursor_position(value),
+ focus_position,
font,
);
@@ -111,70 +119,91 @@ impl text_input::Renderer for Renderer {
};
let (contents_primitive, offset) = if state.is_focused() {
- let (text_value_width, offset) = measure_cursor_and_scroll_offset(
- self,
- text_bounds,
- value,
- size,
- state.cursor().cursor_position(value),
- font,
- );
+ let cursor = state.cursor();
+
+ let (cursor_primitive, offset) = match cursor.state(value) {
+ cursor::State::Index(position) => {
+ let (text_value_width, offset) =
+ measure_cursor_and_scroll_offset(
+ self,
+ text_bounds,
+ value,
+ size,
+ position,
+ font,
+ );
+
+ (
+ Primitive::Quad {
+ bounds: Rectangle {
+ x: text_bounds.x + text_value_width,
+ y: text_bounds.y,
+ width: 1.0,
+ height: text_bounds.height,
+ },
+ background: Background::Color(
+ style_sheet.value_color(),
+ ),
+ border_radius: 0,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
+ },
+ offset,
+ )
+ }
+ cursor::State::Selection { start, end } => {
+ let left = start.min(end);
+ let right = end.max(start);
- let selection = match state.cursor().selection_position() {
- None => Primitive::None,
- Some(_) => {
- let (cursor_left_offset, _) =
+ let (left_position, left_offset) =
measure_cursor_and_scroll_offset(
self,
text_bounds,
value,
size,
- state.cursor().left(),
+ left,
font,
);
- let (cursor_right_offset, _) =
+
+ let (right_position, right_offset) =
measure_cursor_and_scroll_offset(
self,
text_bounds,
value,
size,
- state.cursor().right(),
+ right,
font,
);
- let width = cursor_right_offset - cursor_left_offset;
- Primitive::Quad {
- bounds: Rectangle {
- x: text_bounds.x + cursor_left_offset,
- y: text_bounds.y,
- width,
- height: text_bounds.height,
+
+ let width = right_position - left_position;
+
+ (
+ Primitive::Quad {
+ bounds: Rectangle {
+ x: text_bounds.x + left_position,
+ y: text_bounds.y,
+ width,
+ height: text_bounds.height,
+ },
+ background: Background::Color(
+ style_sheet.selection_color(),
+ ),
+ border_radius: 0,
+ border_width: 0,
+ border_color: Color::TRANSPARENT,
+ },
+ if end == right {
+ right_offset
+ } else {
+ left_offset
},
- background: Background::Color(
- style_sheet.selection_color(),
- ),
- border_radius: 0,
- border_width: 0,
- border_color: Color::TRANSPARENT,
- }
+ )
}
};
- let cursor = Primitive::Quad {
- bounds: Rectangle {
- x: text_bounds.x + text_value_width,
- y: text_bounds.y,
- width: 1.0,
- height: text_bounds.height,
- },
- background: Background::Color(style_sheet.value_color()),
- border_radius: 0,
- border_width: 0,
- border_color: Color::TRANSPARENT,
- };
-
(
Primitive::Group {
- primitives: vec![selection, text_value, cursor],
+ primitives: vec![cursor_primitive, text_value],
},
Vector::new(offset as u32, 0),
)