make more InputState properties private
This commit is contained in:
@@ -191,7 +191,7 @@ struct InputStateSnapshot {
|
||||
marked_range: Option<Range<usize>>,
|
||||
cursor_position: usize,
|
||||
logical_lines: Vec<InputLogicalLine>,
|
||||
scroll_offset: Pixels,
|
||||
scroll_distance: Pixels,
|
||||
line_height: Pixels,
|
||||
}
|
||||
impl InputStateSnapshot {
|
||||
@@ -201,7 +201,7 @@ impl InputStateSnapshot {
|
||||
let marked_range = input_state.marked_range().cloned();
|
||||
let cursor_position = input_state.cursor_position();
|
||||
let logical_lines = input_state.logical_lines.clone();
|
||||
let scroll_offset = input_state.scroll_offset;
|
||||
let scroll_distance = input_state.distance_from_top();
|
||||
let line_height = input_state.line_height();
|
||||
let layout_axis = input_state.layout_style().axis();
|
||||
let should_center_placeholder = matches!(
|
||||
@@ -216,7 +216,7 @@ impl InputStateSnapshot {
|
||||
marked_range,
|
||||
cursor_position,
|
||||
logical_lines,
|
||||
scroll_offset,
|
||||
scroll_distance,
|
||||
line_height,
|
||||
}
|
||||
}
|
||||
@@ -241,6 +241,7 @@ impl<'app> PaintContext<'app> {
|
||||
) {
|
||||
let axis = self.snapshot.layout_axis;
|
||||
let bounds = self.bounds;
|
||||
let scroll_distance = self.snapshot.scroll_distance;
|
||||
window.on_mouse_event({
|
||||
let input = entity.clone();
|
||||
move |event: &MouseDownEvent, phase, window, cx| {
|
||||
@@ -257,7 +258,7 @@ impl<'app> PaintContext<'app> {
|
||||
input.update(cx, |input, cx| {
|
||||
// Converts a screen position to a position relative to the text area origin, adjusted for scroll offset.
|
||||
let text_position = (event.position - bounds.origin)
|
||||
.apply_along(axis, |pos| pos + input.scroll_offset);
|
||||
.apply_along(axis, |pos| pos + scroll_distance);
|
||||
input.on_mouse_down(
|
||||
text_position,
|
||||
event.click_count,
|
||||
@@ -293,7 +294,7 @@ impl<'app> PaintContext<'app> {
|
||||
input.update(cx, |input, cx| {
|
||||
// Converts a screen position to a position relative to the text area origin, adjusted for scroll offset.
|
||||
let text_position = (event.position - bounds.origin)
|
||||
.apply_along(axis, |pos| pos + input.scroll_offset);
|
||||
.apply_along(axis, |pos| pos + scroll_distance);
|
||||
input.on_mouse_move(text_position, cx);
|
||||
});
|
||||
}
|
||||
@@ -330,7 +331,7 @@ impl<'app> PaintContext<'app> {
|
||||
}
|
||||
}
|
||||
};
|
||||
input.scroll_offset = (input.scroll_offset - delta).clamp(px(0.), max_scroll);
|
||||
input.apply_scroll_delta(delta, max_scroll);
|
||||
cx.notify();
|
||||
});
|
||||
}
|
||||
@@ -372,7 +373,7 @@ impl<'app> PaintContext<'app> {
|
||||
fn paint_selection(&self, window: &mut Window) {
|
||||
let one_line = self.snapshot.logical_lines.len() == 1;
|
||||
for line in &self.snapshot.logical_lines {
|
||||
let line_y = line.y_offset - self.snapshot.scroll_offset;
|
||||
let line_y = line.y_offset - self.snapshot.scroll_distance;
|
||||
|
||||
if !one_line {
|
||||
if !self.is_line_visible(line) {
|
||||
@@ -442,7 +443,7 @@ impl<'app> PaintContext<'app> {
|
||||
|
||||
fn paint_text(&self, window: &mut Window, cx: &mut App) {
|
||||
for line_layout in &self.snapshot.logical_lines {
|
||||
let line_y = line_layout.y_offset - self.snapshot.scroll_offset;
|
||||
let line_y = line_layout.y_offset - self.snapshot.scroll_distance;
|
||||
|
||||
if !self.is_line_visible(line_layout) {
|
||||
continue;
|
||||
@@ -499,7 +500,7 @@ impl<'app> PaintContext<'app> {
|
||||
|
||||
fn find_cursor_position_in_layouts(&self) -> Point<Pixels> {
|
||||
for line in &self.snapshot.logical_lines {
|
||||
let line_y = line.y_offset - self.snapshot.scroll_offset;
|
||||
let line_y = line.y_offset - self.snapshot.scroll_distance;
|
||||
|
||||
if !self.is_line_visible(line) {
|
||||
continue;
|
||||
@@ -544,7 +545,7 @@ impl<'app> PaintContext<'app> {
|
||||
}
|
||||
|
||||
fn is_line_visible(&self, line: &InputLogicalLine) -> bool {
|
||||
let line_y = line.y_offset - self.snapshot.scroll_offset;
|
||||
let line_y = line.y_offset - self.snapshot.scroll_distance;
|
||||
let line_bottom = line_y + self.snapshot.line_height * line.visual_line_count as f32;
|
||||
line_bottom >= px(0.) && line_y <= self.bounds.size.height
|
||||
}
|
||||
@@ -565,7 +566,7 @@ impl<'app> PaintContext<'app> {
|
||||
return;
|
||||
};
|
||||
|
||||
let line_y = line.y_offset - self.snapshot.scroll_offset;
|
||||
let line_y = line.y_offset - self.snapshot.scroll_distance;
|
||||
|
||||
let line_start = line.text_range.start;
|
||||
let line_end = line.text_range.end;
|
||||
|
||||
@@ -44,15 +44,15 @@ pub struct InputState {
|
||||
cached_utf16_len: Option<usize>,
|
||||
|
||||
/// The style of layout (single or multiline).
|
||||
pub(super) layout_style: InputLayoutStyle,
|
||||
layout_style: InputLayoutStyle,
|
||||
/// The utf-8 character range that is currently selected by the user.
|
||||
/// NOTE: because each input has its own selection state, its trivial for users to have multiple selections active across multiple inputs at the same time.
|
||||
/// This could be considered undesirable behavior, and doing so would prompt the question of should there be a mechanism to clear selection when focus is lost.
|
||||
pub(super) selected_range: Range<usize>,
|
||||
selected_range: Range<usize>,
|
||||
/// The direction of the selection_range. Forward means providing in iteration order along `content`. Back means reverse iteration order.
|
||||
pub(super) selection_direction: NavigationDirection,
|
||||
selection_direction: NavigationDirection,
|
||||
/// The utf-8 character range of `content` that is currently marked/highlighted.
|
||||
pub(super) marked_range: Option<Range<usize>>,
|
||||
marked_range: Option<Range<usize>>,
|
||||
|
||||
// refreshed each update by the element, for conveinent access in mutations and painting
|
||||
pub(super) layout_data: InputLayoutData,
|
||||
@@ -68,7 +68,7 @@ pub struct InputState {
|
||||
/// The number of times the user has clicked `last_click_position`. Used to determine which click behavior to trigger, depending on single, double, or triple clicks.
|
||||
click_count: usize,
|
||||
/// The distance in pixels from the start of the text a user has scrolled along the layout_style axis (singleline is horizontal, multiline is vertical).
|
||||
pub(super) scroll_offset: Pixels,
|
||||
scroll_distance: Pixels,
|
||||
|
||||
/// The maximum duration between changes to `content` that can be grouped together as a single entry in the history log.
|
||||
history_grouping_interval: Duration,
|
||||
@@ -163,7 +163,7 @@ impl InputState {
|
||||
is_selecting: false,
|
||||
last_click_position: None,
|
||||
click_count: 0,
|
||||
scroll_offset: px(0.),
|
||||
scroll_distance: px(0.),
|
||||
|
||||
history_grouping_interval: super::DEFAULT_GROUP_INTERVAL,
|
||||
history_undo_stack: Vec::new(),
|
||||
@@ -232,6 +232,10 @@ impl InputState {
|
||||
&self.selected_range
|
||||
}
|
||||
|
||||
pub fn selection_direction(&self) -> NavigationDirection {
|
||||
self.selection_direction
|
||||
}
|
||||
|
||||
/// Sets the selection range directly.
|
||||
pub fn set_selected_range(&mut self, range: Range<usize>) {
|
||||
let range = range.start.min(self.content.len())..range.end.min(self.content.len());
|
||||
@@ -254,7 +258,7 @@ impl InputState {
|
||||
|
||||
/// Returns true if the scroll position is at the top.
|
||||
pub fn at_top(&self) -> bool {
|
||||
self.scroll_offset <= px(0.)
|
||||
self.scroll_distance <= px(0.)
|
||||
}
|
||||
|
||||
/// Returns true if the scroll position is at the bottom.
|
||||
@@ -266,7 +270,7 @@ impl InputState {
|
||||
return true;
|
||||
}
|
||||
|
||||
self.scroll_offset + visible_height >= content_height
|
||||
self.scroll_distance + visible_height >= content_height
|
||||
}
|
||||
|
||||
/// Returns the scroll progress as a value from 0.0 (top) to 1.0 (bottom).
|
||||
@@ -279,12 +283,12 @@ impl InputState {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
(self.scroll_offset / max_scroll).clamp(0.0, 1.0)
|
||||
(self.scroll_distance / max_scroll).clamp(0.0, 1.0)
|
||||
}
|
||||
|
||||
/// Returns how far the content is scrolled from the top in pixels.
|
||||
pub fn distance_from_top(&self) -> Pixels {
|
||||
self.scroll_offset.max(px(0.))
|
||||
self.scroll_distance.max(px(0.))
|
||||
}
|
||||
|
||||
/// Returns how far the content is from the bottom in pixels.
|
||||
@@ -297,7 +301,7 @@ impl InputState {
|
||||
return px(0.);
|
||||
}
|
||||
|
||||
(max_scroll - self.scroll_offset).max(px(0.))
|
||||
(max_scroll - self.scroll_distance).max(px(0.))
|
||||
}
|
||||
|
||||
/// Configures how long the input will wait between user-input changes to create new logs in the history for undo/redo.
|
||||
@@ -347,7 +351,7 @@ impl InputState {
|
||||
self.cached_utf16_len = Some(cached_len - removed_utf16_len + added_utf16_len);
|
||||
}
|
||||
|
||||
self.replace_range(range.clone(), &text_to_insert);
|
||||
self.replace_text_at_range(range.clone(), &text_to_insert);
|
||||
|
||||
self.selected_range =
|
||||
range.start + text_to_insert.len()..range.start + text_to_insert.len();
|
||||
@@ -834,8 +838,12 @@ impl InputState {
|
||||
self.layout_data.line_height
|
||||
}
|
||||
|
||||
pub(super) fn set_marked_range(&mut self, range: Option<Range<usize>>) {
|
||||
self.marked_range = range;
|
||||
}
|
||||
|
||||
/// Replaces the provided utf-8 character range with the provided text
|
||||
pub(super) fn replace_range(&mut self, range: Range<usize>, text: &str) {
|
||||
pub(super) fn replace_text_at_range(&mut self, range: Range<usize>, text: &str) {
|
||||
self.content.replace_range(range, &text);
|
||||
}
|
||||
|
||||
@@ -944,6 +952,10 @@ impl InputState {
|
||||
self.content.len()
|
||||
}
|
||||
|
||||
pub(super) fn apply_scroll_delta(&mut self, delta: Pixels, max: Pixels) {
|
||||
self.scroll_distance = (self.scroll_distance - delta).clamp(px(0.), max);
|
||||
}
|
||||
|
||||
pub(super) fn scroll_to_cursor(&mut self) {
|
||||
if self.logical_lines.is_empty() {
|
||||
return;
|
||||
@@ -971,19 +983,20 @@ impl InputState {
|
||||
px(0.)
|
||||
};
|
||||
|
||||
let visible_left = self.scroll_offset;
|
||||
let visible_right = self.scroll_offset + self.layout_data.available_size.width;
|
||||
let visible_left = self.scroll_distance;
|
||||
let visible_right = self.scroll_distance + self.layout_data.available_size.width;
|
||||
|
||||
// Add some padding so cursor isn't right at the edge
|
||||
let padding = px(2.0);
|
||||
|
||||
if cursor_x < visible_left + padding {
|
||||
self.scroll_offset = (cursor_x - padding).max(px(0.));
|
||||
self.scroll_distance = (cursor_x - padding).max(px(0.));
|
||||
} else if cursor_x > visible_right - padding {
|
||||
self.scroll_offset = cursor_x - self.layout_data.available_size.width + padding;
|
||||
self.scroll_distance =
|
||||
cursor_x - self.layout_data.available_size.width + padding;
|
||||
}
|
||||
|
||||
self.scroll_offset = self.scroll_offset.max(px(0.));
|
||||
self.scroll_distance = self.scroll_distance.max(px(0.));
|
||||
}
|
||||
InputLayoutStyle::MultiLine => {
|
||||
if self.layout_data.available_size.height <= px(0.) {
|
||||
@@ -1015,18 +1028,18 @@ impl InputState {
|
||||
line.y_offset
|
||||
};
|
||||
|
||||
let visible_top = self.scroll_offset;
|
||||
let visible_top = self.scroll_distance;
|
||||
let visible_bottom =
|
||||
self.scroll_offset + self.layout_data.available_size.height;
|
||||
self.scroll_distance + self.layout_data.available_size.height;
|
||||
|
||||
if cursor_visual_y < visible_top {
|
||||
self.scroll_offset = cursor_visual_y;
|
||||
self.scroll_distance = cursor_visual_y;
|
||||
} else if cursor_visual_y + line_height > visible_bottom {
|
||||
self.scroll_offset = (cursor_visual_y + line_height)
|
||||
self.scroll_distance = (cursor_visual_y + line_height)
|
||||
- self.layout_data.available_size.height;
|
||||
}
|
||||
|
||||
self.scroll_offset = self.scroll_offset.max(px(0.));
|
||||
self.scroll_distance = self.scroll_distance.max(px(0.));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ impl EntityInputHandler for super::InputState {
|
||||
_cx: &mut Context<Self>,
|
||||
) -> Option<UTF16Selection> {
|
||||
Some(UTF16Selection {
|
||||
range: self.utf_range_8to16(&self.selected_range),
|
||||
reversed: self.selection_direction == NavigationDirection::Back,
|
||||
range: self.utf_range_8to16(self.selected_range()),
|
||||
reversed: self.selection_direction() == NavigationDirection::Back,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -38,13 +38,13 @@ impl EntityInputHandler for super::InputState {
|
||||
_window: &mut Window,
|
||||
_cx: &mut Context<Self>,
|
||||
) -> Option<Range<usize>> {
|
||||
self.marked_range
|
||||
self.marked_range()
|
||||
.as_ref()
|
||||
.map(|range| self.utf_range_8to16(range))
|
||||
}
|
||||
|
||||
fn unmark_text(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {
|
||||
self.marked_range = None;
|
||||
self.set_marked_range(None);
|
||||
}
|
||||
|
||||
fn replace_text_in_range(
|
||||
@@ -57,21 +57,21 @@ impl EntityInputHandler for super::InputState {
|
||||
let range = range_utf16
|
||||
.as_ref()
|
||||
.map(|range_utf16| self.utf_range_16to8(range_utf16))
|
||||
.or(self.marked_range.clone())
|
||||
.unwrap_or(self.selected_range.clone());
|
||||
.or(self.marked_range().cloned())
|
||||
.unwrap_or(self.selected_range().clone());
|
||||
let range = range.start.min(self.content().len())..range.end.min(self.content().len());
|
||||
|
||||
let text_to_insert = self.layout_style.sanitize_content(new_text);
|
||||
let text_to_insert = self.layout_style().sanitize_content(new_text);
|
||||
|
||||
// Record patch for undo before modifying content
|
||||
self.push_undo_patch(range.clone(), text_to_insert.len());
|
||||
self.push_undo_patch(range.clone(), text_to_insert.len());
|
||||
self.update_utf16_len(range.clone(), &text_to_insert);
|
||||
self.replace_range(range.clone(), &text_to_insert);
|
||||
|
||||
self.selected_range =
|
||||
range.start + text_to_insert.len()..range.start + text_to_insert.len();
|
||||
self.marked_range.take();
|
||||
self.update_utf16_len(range.clone(), &text_to_insert);
|
||||
self.replace_text_at_range(range.clone(), &text_to_insert);
|
||||
self.set_selected_range(
|
||||
range.start + text_to_insert.len()..range.start + text_to_insert.len(),
|
||||
);
|
||||
self.set_marked_range(None);
|
||||
self.layout_data.dirty = true;
|
||||
|
||||
self.pause_cursor_blink(cx);
|
||||
@@ -90,28 +90,27 @@ impl EntityInputHandler for super::InputState {
|
||||
let range = range_utf16
|
||||
.as_ref()
|
||||
.map(|range_utf16| self.utf_range_16to8(range_utf16))
|
||||
.or(self.marked_range.clone())
|
||||
.unwrap_or(self.selected_range.clone());
|
||||
.or(self.marked_range().cloned())
|
||||
.unwrap_or(self.selected_range().clone());
|
||||
let range = range.start.min(self.content().len())..range.end.min(self.content().len());
|
||||
|
||||
let text_to_insert = self.layout_style.sanitize_content(new_text);
|
||||
let text_to_insert = self.layout_style().sanitize_content(new_text);
|
||||
|
||||
self.update_utf16_len(range.clone(), &text_to_insert);
|
||||
self.replace_range(range.clone(), &text_to_insert);
|
||||
|
||||
if !text_to_insert.is_empty() {
|
||||
self.marked_range = Some(range.start..range.start + text_to_insert.len());
|
||||
} else {
|
||||
self.marked_range = None;
|
||||
}
|
||||
|
||||
self.selected_range = new_selected_range_utf16
|
||||
.as_ref()
|
||||
.map(|range_utf16| self.utf_range_16to8(range_utf16))
|
||||
.map(|new_range| new_range.start + range.start..new_range.end + range.start)
|
||||
.unwrap_or_else(|| {
|
||||
self.replace_text_at_range(range.clone(), &text_to_insert);
|
||||
self.set_marked_range(match text_to_insert.is_empty() {
|
||||
true => None,
|
||||
false => Some(range.start..range.start + text_to_insert.len()),
|
||||
});
|
||||
self.set_selected_range({
|
||||
let new_range = new_selected_range_utf16.as_ref();
|
||||
let new_range = new_range.map(|range_utf16| self.utf_range_16to8(range_utf16));
|
||||
let new_range = new_range
|
||||
.map(|new_range| new_range.start + range.start..new_range.end + range.start);
|
||||
new_range.unwrap_or_else(|| {
|
||||
range.start + text_to_insert.len()..range.start + text_to_insert.len()
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
self.layout_data.dirty = true;
|
||||
cx.emit(InputStateEvent::TextChanged);
|
||||
|
||||
Reference in New Issue
Block a user