Fix some edge cases for the cursor movement
This commit is contained in:
parent
c84431e473
commit
7494026139
3 changed files with 146 additions and 88 deletions
|
@ -164,7 +164,7 @@ impl Font {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn layout_multiline(&self, text: String, max_width_in_points: f32) -> Galley {
|
pub fn layout_multiline(&self, text: String, max_width_in_points: f32) -> Galley {
|
||||||
let line_spacing = self.row_height();
|
let row_height = self.row_height();
|
||||||
let mut cursor_y = 0.0;
|
let mut cursor_y = 0.0;
|
||||||
let mut rows = Vec::new();
|
let mut rows = Vec::new();
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ impl Font {
|
||||||
row.y_max += cursor_y;
|
row.y_max += cursor_y;
|
||||||
}
|
}
|
||||||
cursor_y = paragraph_rows.last().unwrap().y_max;
|
cursor_y = paragraph_rows.last().unwrap().y_max;
|
||||||
cursor_y += line_spacing * 0.4; // Extra spacing between paragraphs. TODO: less hacky
|
cursor_y += row_height * 0.4; // Extra spacing between paragraphs. TODO: less hacky
|
||||||
|
|
||||||
rows.append(&mut paragraph_rows);
|
rows.append(&mut paragraph_rows);
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ impl Font {
|
||||||
rows.push(Row {
|
rows.push(Row {
|
||||||
x_offsets: vec![0.0],
|
x_offsets: vec![0.0],
|
||||||
y_min: cursor_y,
|
y_min: cursor_y,
|
||||||
y_max: cursor_y + line_spacing,
|
y_max: cursor_y + row_height,
|
||||||
ends_with_newline: false,
|
ends_with_newline: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ pub struct CCursor {
|
||||||
|
|
||||||
/// If this cursors sits right at the border of a wrapped row break (NOT paragraph break)
|
/// If this cursors sits right at the border of a wrapped row break (NOT paragraph break)
|
||||||
/// do we prefer the next row?
|
/// do we prefer the next row?
|
||||||
|
/// This is *almost* always what you want, *except* for when
|
||||||
|
/// explicitly clicking the end of a row or pressing the end key.
|
||||||
pub prefer_next_row: bool,
|
pub prefer_next_row: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,6 +100,8 @@ pub struct PCursor {
|
||||||
|
|
||||||
/// If this cursors sits right at the border of a wrapped row break (NOT paragraph break)
|
/// If this cursors sits right at the border of a wrapped row break (NOT paragraph break)
|
||||||
/// do we prefer the next row?
|
/// do we prefer the next row?
|
||||||
|
/// This is *almost* always what you want, *except* for when
|
||||||
|
/// explicitly clicking the end of a row or pressing the end key.
|
||||||
pub prefer_next_row: bool,
|
pub prefer_next_row: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,15 +240,16 @@ impl Galley {
|
||||||
// Right paragraph, but is it the right row in the paragraph?
|
// Right paragraph, but is it the right row in the paragraph?
|
||||||
|
|
||||||
if it.offset <= pcursor.offset
|
if it.offset <= pcursor.offset
|
||||||
&& pcursor.offset <= it.offset + row.char_count_excluding_newline()
|
&& (pcursor.offset <= it.offset + row.char_count_excluding_newline()
|
||||||
|
|| row.ends_with_newline)
|
||||||
{
|
{
|
||||||
let column = pcursor.offset - it.offset;
|
let column = pcursor.offset - it.offset;
|
||||||
let column = column.at_most(row.char_count_excluding_newline());
|
let column = column.at_most(row.char_count_excluding_newline());
|
||||||
|
|
||||||
let select_next_line_instead = pcursor.prefer_next_row
|
let select_next_row_instead = pcursor.prefer_next_row
|
||||||
&& !row.ends_with_newline
|
&& !row.ends_with_newline
|
||||||
&& column == row.char_count_excluding_newline();
|
&& column >= row.char_count_excluding_newline();
|
||||||
if !select_next_line_instead {
|
if !select_next_row_instead {
|
||||||
return vec2(row.x_offsets[column], row.y_min);
|
return vec2(row.x_offsets[column], row.y_min);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,31 +272,32 @@ impl Galley {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cursor at the given position within the galley
|
/// Cursor at the given position within the galley
|
||||||
pub fn cursor_at(&self, pos: Vec2) -> Cursor {
|
pub fn cursor_from_pos(&self, pos: Vec2) -> Cursor {
|
||||||
let mut best_y_dist = f32::INFINITY;
|
let mut best_y_dist = f32::INFINITY;
|
||||||
let mut cursor = Cursor::default();
|
let mut cursor = Cursor::default();
|
||||||
|
|
||||||
let mut ccursor_index = 0;
|
let mut ccursor_index = 0;
|
||||||
let mut pcursor_it = PCursor::default();
|
let mut pcursor_it = PCursor::default();
|
||||||
|
|
||||||
for (line_nr, row) in self.rows.iter().enumerate() {
|
for (row_nr, row) in self.rows.iter().enumerate() {
|
||||||
let y_dist = (row.y_min - pos.y).abs().min((row.y_max - pos.y).abs());
|
let y_dist = (row.y_min - pos.y).abs().min((row.y_max - pos.y).abs());
|
||||||
if y_dist < best_y_dist {
|
if y_dist < best_y_dist {
|
||||||
best_y_dist = y_dist;
|
best_y_dist = y_dist;
|
||||||
let column = row.char_at(pos.x);
|
let column = row.char_at(pos.x);
|
||||||
|
let prefer_next_row = column < row.char_count_excluding_newline();
|
||||||
cursor = Cursor {
|
cursor = Cursor {
|
||||||
ccursor: CCursor {
|
ccursor: CCursor {
|
||||||
index: ccursor_index + column,
|
index: ccursor_index + column,
|
||||||
prefer_next_row: column == 0,
|
prefer_next_row,
|
||||||
},
|
},
|
||||||
rcursor: RCursor {
|
rcursor: RCursor {
|
||||||
row: line_nr,
|
row: row_nr,
|
||||||
column,
|
column,
|
||||||
},
|
},
|
||||||
pcursor: PCursor {
|
pcursor: PCursor {
|
||||||
paragraph: pcursor_it.paragraph,
|
paragraph: pcursor_it.paragraph,
|
||||||
offset: pcursor_it.offset + column,
|
offset: pcursor_it.offset + column,
|
||||||
prefer_next_row: column == 0,
|
prefer_next_row,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,13 +330,13 @@ impl Galley {
|
||||||
prefer_next_row: true,
|
prefer_next_row: true,
|
||||||
};
|
};
|
||||||
for row in &self.rows {
|
for row in &self.rows {
|
||||||
let line_char_count = row.char_count_including_newline();
|
let row_char_count = row.char_count_including_newline();
|
||||||
ccursor.index += line_char_count;
|
ccursor.index += row_char_count;
|
||||||
if row.ends_with_newline {
|
if row.ends_with_newline {
|
||||||
pcursor.paragraph += 1;
|
pcursor.paragraph += 1;
|
||||||
pcursor.offset = 0;
|
pcursor.offset = 0;
|
||||||
} else {
|
} else {
|
||||||
pcursor.offset += line_char_count;
|
pcursor.offset += row_char_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cursor {
|
Cursor {
|
||||||
|
@ -355,36 +361,36 @@ impl Galley {
|
||||||
|
|
||||||
/// ## Cursor conversions
|
/// ## Cursor conversions
|
||||||
impl Galley {
|
impl Galley {
|
||||||
// TODO: return identical cursor, or clamp?
|
// The returned cursor is clamped.
|
||||||
pub fn from_ccursor(&self, ccursor: CCursor) -> Cursor {
|
pub fn from_ccursor(&self, ccursor: CCursor) -> Cursor {
|
||||||
let prefer_next_line = ccursor.prefer_next_row;
|
let prefer_next_row = ccursor.prefer_next_row;
|
||||||
let mut ccursor_it = CCursor {
|
let mut ccursor_it = CCursor {
|
||||||
index: 0,
|
index: 0,
|
||||||
prefer_next_row: prefer_next_line,
|
prefer_next_row,
|
||||||
};
|
};
|
||||||
let mut pcursor_it = PCursor {
|
let mut pcursor_it = PCursor {
|
||||||
paragraph: 0,
|
paragraph: 0,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
prefer_next_row: prefer_next_line,
|
prefer_next_row,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (line_nr, row) in self.rows.iter().enumerate() {
|
for (row_nr, row) in self.rows.iter().enumerate() {
|
||||||
let line_char_count = row.char_count_excluding_newline();
|
let row_char_count = row.char_count_excluding_newline();
|
||||||
|
|
||||||
if ccursor_it.index <= ccursor.index
|
if ccursor_it.index <= ccursor.index
|
||||||
&& ccursor.index <= ccursor_it.index + line_char_count
|
&& ccursor.index <= ccursor_it.index + row_char_count
|
||||||
{
|
{
|
||||||
let column = ccursor.index - ccursor_it.index;
|
let column = ccursor.index - ccursor_it.index;
|
||||||
|
|
||||||
let select_next_line_instead = prefer_next_line
|
let select_next_row_instead = prefer_next_row
|
||||||
&& !row.ends_with_newline
|
&& !row.ends_with_newline
|
||||||
&& column == row.char_count_excluding_newline();
|
&& column >= row.char_count_excluding_newline();
|
||||||
if !select_next_line_instead {
|
if !select_next_row_instead {
|
||||||
pcursor_it.offset += column;
|
pcursor_it.offset += column;
|
||||||
return Cursor {
|
return Cursor {
|
||||||
ccursor,
|
ccursor,
|
||||||
rcursor: RCursor {
|
rcursor: RCursor {
|
||||||
row: line_nr,
|
row: row_nr,
|
||||||
column,
|
column,
|
||||||
},
|
},
|
||||||
pcursor: pcursor_it,
|
pcursor: pcursor_it,
|
||||||
|
@ -407,40 +413,38 @@ impl Galley {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: return identical cursor, or clamp?
|
|
||||||
pub fn from_rcursor(&self, rcursor: RCursor) -> Cursor {
|
pub fn from_rcursor(&self, rcursor: RCursor) -> Cursor {
|
||||||
if rcursor.row >= self.rows.len() {
|
if rcursor.row >= self.rows.len() {
|
||||||
return self.end();
|
return self.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
let prefer_next_line = rcursor.column == 0;
|
let prefer_next_row =
|
||||||
|
rcursor.column < self.rows[rcursor.row].char_count_excluding_newline();
|
||||||
let mut ccursor_it = CCursor {
|
let mut ccursor_it = CCursor {
|
||||||
index: 0,
|
index: 0,
|
||||||
prefer_next_row: prefer_next_line,
|
prefer_next_row,
|
||||||
};
|
};
|
||||||
let mut pcursor_it = PCursor {
|
let mut pcursor_it = PCursor {
|
||||||
paragraph: 0,
|
paragraph: 0,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
prefer_next_row: prefer_next_line,
|
prefer_next_row,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (line_nr, row) in self.rows.iter().enumerate() {
|
for (row_nr, row) in self.rows.iter().enumerate() {
|
||||||
if line_nr == rcursor.row {
|
if row_nr == rcursor.row {
|
||||||
let column = rcursor.column.at_most(row.char_count_excluding_newline());
|
ccursor_it.index += rcursor.column.at_most(row.char_count_excluding_newline());
|
||||||
|
|
||||||
let select_next_line_instead = prefer_next_line
|
if row.ends_with_newline {
|
||||||
&& !row.ends_with_newline
|
// Allow offset to go beyond the end of the paragraph
|
||||||
&& column == row.char_count_excluding_newline();
|
pcursor_it.offset += rcursor.column;
|
||||||
|
} else {
|
||||||
if !select_next_line_instead {
|
pcursor_it.offset += rcursor.column.at_most(row.char_count_excluding_newline());
|
||||||
ccursor_it.index += column;
|
|
||||||
pcursor_it.offset += column;
|
|
||||||
return Cursor {
|
|
||||||
ccursor: ccursor_it,
|
|
||||||
rcursor,
|
|
||||||
pcursor: pcursor_it,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
return Cursor {
|
||||||
|
ccursor: ccursor_it,
|
||||||
|
rcursor,
|
||||||
|
pcursor: pcursor_it,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
ccursor_it.index += row.char_count_including_newline();
|
ccursor_it.index += row.char_count_including_newline();
|
||||||
if row.ends_with_newline {
|
if row.ends_with_newline {
|
||||||
|
@ -459,36 +463,38 @@ impl Galley {
|
||||||
|
|
||||||
// TODO: return identical cursor, or clamp?
|
// TODO: return identical cursor, or clamp?
|
||||||
pub fn from_pcursor(&self, pcursor: PCursor) -> Cursor {
|
pub fn from_pcursor(&self, pcursor: PCursor) -> Cursor {
|
||||||
let prefer_next_line = pcursor.prefer_next_row;
|
let prefer_next_row = pcursor.prefer_next_row;
|
||||||
let mut ccursor_it = CCursor {
|
let mut ccursor_it = CCursor {
|
||||||
index: 0,
|
index: 0,
|
||||||
prefer_next_row: prefer_next_line,
|
prefer_next_row,
|
||||||
};
|
};
|
||||||
let mut pcursor_it = PCursor {
|
let mut pcursor_it = PCursor {
|
||||||
paragraph: 0,
|
paragraph: 0,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
prefer_next_row: prefer_next_line,
|
prefer_next_row,
|
||||||
};
|
};
|
||||||
|
|
||||||
for (line_nr, row) in self.rows.iter().enumerate() {
|
for (row_nr, row) in self.rows.iter().enumerate() {
|
||||||
if pcursor_it.paragraph == pcursor.paragraph {
|
if pcursor_it.paragraph == pcursor.paragraph {
|
||||||
// Right paragraph, but is it the right row in the paragraph?
|
// Right paragraph, but is it the right row in the paragraph?
|
||||||
|
|
||||||
if pcursor_it.offset <= pcursor.offset
|
if pcursor_it.offset <= pcursor.offset
|
||||||
&& pcursor.offset <= pcursor_it.offset + row.char_count_excluding_newline()
|
&& (pcursor.offset <= pcursor_it.offset + row.char_count_excluding_newline()
|
||||||
|
|| row.ends_with_newline)
|
||||||
{
|
{
|
||||||
let column = pcursor.offset - pcursor_it.offset;
|
let column = pcursor.offset - pcursor_it.offset;
|
||||||
let column = column.at_most(row.char_count_excluding_newline());
|
|
||||||
|
|
||||||
let select_next_line_instead = pcursor.prefer_next_row
|
let select_next_row_instead = pcursor.prefer_next_row
|
||||||
&& !row.ends_with_newline
|
&& !row.ends_with_newline
|
||||||
&& column == row.char_count_excluding_newline();
|
&& column >= row.char_count_excluding_newline();
|
||||||
if !select_next_line_instead {
|
|
||||||
ccursor_it.index += column;
|
if !select_next_row_instead {
|
||||||
|
ccursor_it.index += column.at_most(row.char_count_excluding_newline());
|
||||||
|
|
||||||
return Cursor {
|
return Cursor {
|
||||||
ccursor: ccursor_it,
|
ccursor: ccursor_it,
|
||||||
rcursor: RCursor {
|
rcursor: RCursor {
|
||||||
row: line_nr,
|
row: row_nr,
|
||||||
column,
|
column,
|
||||||
},
|
},
|
||||||
pcursor,
|
pcursor,
|
||||||
|
@ -519,44 +525,97 @@ impl Galley {
|
||||||
if cursor.ccursor.index == 0 {
|
if cursor.ccursor.index == 0 {
|
||||||
Default::default()
|
Default::default()
|
||||||
} else {
|
} else {
|
||||||
self.from_ccursor(cursor.ccursor - 1)
|
let ccursor = CCursor {
|
||||||
|
index: cursor.ccursor.index,
|
||||||
|
prefer_next_row: true, // default to this when navigating. It is more often useful to put cursor at the begging of a row than at the end.
|
||||||
|
};
|
||||||
|
self.from_ccursor(ccursor - 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_right_one_character(&self, cursor: &Cursor) -> Cursor {
|
pub fn cursor_right_one_character(&self, cursor: &Cursor) -> Cursor {
|
||||||
self.from_ccursor(cursor.ccursor + 1)
|
let ccursor = CCursor {
|
||||||
|
index: cursor.ccursor.index,
|
||||||
|
prefer_next_row: true, // default to this when navigating. It is more often useful to put cursor at the begging of a row than at the end.
|
||||||
|
};
|
||||||
|
self.from_ccursor(ccursor + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_up_one_line(&self, cursor: &Cursor) -> Cursor {
|
pub fn cursor_up_one_row(&self, cursor: &Cursor) -> Cursor {
|
||||||
if cursor.rcursor.row == 0 {
|
if cursor.rcursor.row == 0 {
|
||||||
Cursor::default()
|
Cursor::default()
|
||||||
} else {
|
} else {
|
||||||
let x = self.pos_from_cursor(cursor).x;
|
let new_row = cursor.rcursor.row - 1;
|
||||||
let row = cursor.rcursor.row - 1;
|
|
||||||
let column = self.rows[row].char_at(x).max(cursor.rcursor.column);
|
let cursor_is_beyond_end_of_current_row = cursor.rcursor.column
|
||||||
self.from_rcursor(RCursor { row, column })
|
>= self.rows[cursor.rcursor.row].char_count_excluding_newline();
|
||||||
|
|
||||||
|
let new_rcursor = if cursor_is_beyond_end_of_current_row {
|
||||||
|
// keep same column
|
||||||
|
RCursor {
|
||||||
|
row: new_row,
|
||||||
|
column: cursor.rcursor.column,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// keep same X coord
|
||||||
|
let x = self.pos_from_cursor(cursor).x;
|
||||||
|
let column = if x > self.rows[new_row].max_x() {
|
||||||
|
// beyond the end of this row - keep same colum
|
||||||
|
cursor.rcursor.column
|
||||||
|
} else {
|
||||||
|
self.rows[new_row].char_at(x)
|
||||||
|
};
|
||||||
|
RCursor {
|
||||||
|
row: new_row,
|
||||||
|
column,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.from_rcursor(new_rcursor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_down_one_line(&self, cursor: &Cursor) -> Cursor {
|
pub fn cursor_down_one_row(&self, cursor: &Cursor) -> Cursor {
|
||||||
if cursor.rcursor.row + 1 < self.rows.len() {
|
if cursor.rcursor.row + 1 < self.rows.len() {
|
||||||
let x = self.pos_from_cursor(cursor).x;
|
let new_row = cursor.rcursor.row + 1;
|
||||||
let row = cursor.rcursor.row + 1;
|
|
||||||
let column = self.rows[row].char_at(x).max(cursor.rcursor.column);
|
let cursor_is_beyond_end_of_current_row = cursor.rcursor.column
|
||||||
self.from_rcursor(RCursor { row, column })
|
>= self.rows[cursor.rcursor.row].char_count_excluding_newline();
|
||||||
|
|
||||||
|
let new_rcursor = if cursor_is_beyond_end_of_current_row {
|
||||||
|
// keep same column
|
||||||
|
RCursor {
|
||||||
|
row: new_row,
|
||||||
|
column: cursor.rcursor.column,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// keep same X coord
|
||||||
|
let x = self.pos_from_cursor(cursor).x;
|
||||||
|
let column = if x > self.rows[new_row].max_x() {
|
||||||
|
// beyond the end of the next row - keep same column
|
||||||
|
cursor.rcursor.column
|
||||||
|
} else {
|
||||||
|
self.rows[new_row].char_at(x)
|
||||||
|
};
|
||||||
|
RCursor {
|
||||||
|
row: new_row,
|
||||||
|
column,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.from_rcursor(new_rcursor)
|
||||||
} else {
|
} else {
|
||||||
self.end()
|
self.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_begin_of_line(&self, cursor: &Cursor) -> Cursor {
|
pub fn cursor_begin_of_row(&self, cursor: &Cursor) -> Cursor {
|
||||||
self.from_rcursor(RCursor {
|
self.from_rcursor(RCursor {
|
||||||
row: cursor.rcursor.row,
|
row: cursor.rcursor.row,
|
||||||
column: 0,
|
column: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cursor_end_of_line(&self, cursor: &Cursor) -> Cursor {
|
pub fn cursor_end_of_row(&self, cursor: &Cursor) -> Cursor {
|
||||||
self.from_rcursor(RCursor {
|
self.from_rcursor(RCursor {
|
||||||
row: cursor.rcursor.row,
|
row: cursor.rcursor.row,
|
||||||
column: self.rows[cursor.rcursor.row].char_count_excluding_newline(),
|
column: self.rows[cursor.rcursor.row].char_count_excluding_newline(),
|
||||||
|
@ -735,11 +794,11 @@ fn test_text_layout() {
|
||||||
|
|
||||||
let cursor = Cursor::default();
|
let cursor = Cursor::default();
|
||||||
|
|
||||||
assert_eq!(galley.cursor_up_one_line(&cursor), cursor);
|
assert_eq!(galley.cursor_up_one_row(&cursor), cursor);
|
||||||
assert_eq!(galley.cursor_begin_of_line(&cursor), cursor);
|
assert_eq!(galley.cursor_begin_of_row(&cursor), cursor);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
galley.cursor_end_of_line(&cursor),
|
galley.cursor_end_of_row(&cursor),
|
||||||
Cursor {
|
Cursor {
|
||||||
ccursor: CCursor::new(5),
|
ccursor: CCursor::new(5),
|
||||||
rcursor: RCursor { row: 0, column: 5 },
|
rcursor: RCursor { row: 0, column: 5 },
|
||||||
|
@ -752,7 +811,7 @@ fn test_text_layout() {
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
galley.cursor_down_one_line(&cursor),
|
galley.cursor_down_one_row(&cursor),
|
||||||
Cursor {
|
Cursor {
|
||||||
ccursor: CCursor::new(5),
|
ccursor: CCursor::new(5),
|
||||||
rcursor: RCursor { row: 1, column: 0 },
|
rcursor: RCursor { row: 1, column: 0 },
|
||||||
|
@ -766,7 +825,7 @@ fn test_text_layout() {
|
||||||
|
|
||||||
let cursor = Cursor::default();
|
let cursor = Cursor::default();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
galley.cursor_down_one_line(&galley.cursor_down_one_line(&cursor)),
|
galley.cursor_down_one_row(&galley.cursor_down_one_row(&cursor)),
|
||||||
Cursor {
|
Cursor {
|
||||||
ccursor: CCursor::new(11),
|
ccursor: CCursor::new(11),
|
||||||
rcursor: RCursor { row: 2, column: 0 },
|
rcursor: RCursor { row: 2, column: 0 },
|
||||||
|
@ -779,13 +838,13 @@ fn test_text_layout() {
|
||||||
);
|
);
|
||||||
|
|
||||||
let cursor = galley.end();
|
let cursor = galley.end();
|
||||||
assert_eq!(galley.cursor_down_one_line(&cursor), cursor);
|
assert_eq!(galley.cursor_down_one_row(&cursor), cursor);
|
||||||
|
|
||||||
let cursor = galley.end();
|
let cursor = galley.end();
|
||||||
assert!(galley.cursor_up_one_line(&galley.end()) != cursor);
|
assert!(galley.cursor_up_one_row(&galley.end()) != cursor);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
galley.cursor_up_one_line(&galley.end()),
|
galley.cursor_up_one_row(&galley.end()),
|
||||||
Cursor {
|
Cursor {
|
||||||
ccursor: CCursor::new(15),
|
ccursor: CCursor::new(15),
|
||||||
rcursor: RCursor { row: 2, column: 10 },
|
rcursor: RCursor { row: 2, column: 10 },
|
||||||
|
|
|
@ -181,7 +181,11 @@ impl<'t> Widget for TextEdit<'t> {
|
||||||
if response.clicked && enabled {
|
if response.clicked && enabled {
|
||||||
ui.memory().request_kb_focus(id);
|
ui.memory().request_kb_focus(id);
|
||||||
if let Some(mouse_pos) = ui.input().mouse.pos {
|
if let Some(mouse_pos) = ui.input().mouse.pos {
|
||||||
state.pcursor = Some(galley.cursor_at(mouse_pos - response.rect.min).pcursor);
|
state.pcursor = Some(
|
||||||
|
galley
|
||||||
|
.cursor_from_pos(mouse_pos - response.rect.min)
|
||||||
|
.pcursor,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if ui.input().mouse.click || (ui.input().mouse.pressed && !response.hovered) {
|
} else if ui.input().mouse.click || (ui.input().mouse.pressed && !response.hovered) {
|
||||||
// User clicked somewhere else
|
// User clicked somewhere else
|
||||||
|
@ -331,8 +335,6 @@ fn on_key_press(
|
||||||
galley: &Galley,
|
galley: &Galley,
|
||||||
key: Key,
|
key: Key,
|
||||||
) -> Option<CCursor> {
|
) -> Option<CCursor> {
|
||||||
// eprintln!("on_key_press before: '{}', cursor at {}", text, cursor);
|
|
||||||
|
|
||||||
match key {
|
match key {
|
||||||
Key::Backspace if cursor.ccursor.index > 0 => {
|
Key::Backspace if cursor.ccursor.index > 0 => {
|
||||||
*cursor = galley.from_ccursor(cursor.ccursor - 1);
|
*cursor = galley.from_ccursor(cursor.ccursor - 1);
|
||||||
|
@ -358,12 +360,11 @@ fn on_key_press(
|
||||||
Key::Enter => unreachable!("Should have been handled earlier"),
|
Key::Enter => unreachable!("Should have been handled earlier"),
|
||||||
|
|
||||||
Key::Home => {
|
Key::Home => {
|
||||||
// To start of line:
|
*cursor = galley.cursor_begin_of_row(cursor);
|
||||||
*cursor = galley.cursor_begin_of_line(cursor);
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Key::End => {
|
Key::End => {
|
||||||
*cursor = galley.cursor_end_of_line(cursor);
|
*cursor = galley.cursor_end_of_row(cursor);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Key::Left => {
|
Key::Left => {
|
||||||
|
@ -375,15 +376,13 @@ fn on_key_press(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Key::Up => {
|
Key::Up => {
|
||||||
*cursor = galley.cursor_up_one_line(cursor);
|
*cursor = galley.cursor_up_one_row(cursor);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Key::Down => {
|
Key::Down => {
|
||||||
*cursor = galley.cursor_down_one_line(cursor);
|
*cursor = galley.cursor_down_one_row(cursor);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
|
||||||
// eprintln!("on_key_press after: '{}', cursor at {}\n", text, cursor);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue