Skip to content

Commit

Permalink
scroll into view (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
robtfm authored Aug 8, 2024
1 parent 2cd2fa8 commit b4f7622
Showing 1 changed file with 98 additions and 1 deletion.
99 changes: 98 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ use bevy::{
ecs::system::SystemParam,
input::keyboard::{Key, KeyboardInput},
prelude::*,
text::BreakLineOn,
render::camera::RenderTarget,
text::{BreakLineOn, TextLayoutInfo},
window::{PrimaryWindow, WindowRef},
};

/// A Bevy `Plugin` providing the systems and assets required to make a [`TextInputBundle`] work.
Expand Down Expand Up @@ -58,6 +60,7 @@ impl Plugin for TextInputPlugin {
show_hide_cursor,
update_style,
show_hide_placeholder,
scroll_with_cursor,
)
.in_set(TextInputSystem),
)
Expand Down Expand Up @@ -377,6 +380,100 @@ fn update_value(
}
}

fn scroll_with_cursor(
mut texts: Query<
(
&TextLayoutInfo,
&mut Style,
&Node,
&Parent,
Option<&TargetCamera>,
),
(With<TextInputInner>, Changed<TextLayoutInfo>),
>,
mut parents: Query<(&Node, &mut Style), Without<TextInputInner>>,
cameras: Query<&Camera>,
all_windows: Query<&Window>,
primary_window: Query<&Window, With<PrimaryWindow>>,
) {
for (layout, mut style, child_node, parent, target_camera) in texts.iter_mut() {
let Ok((parent_node, mut parent_style)) = parents.get_mut(parent.get()) else {
continue;
};

match layout.glyphs.last().map(|g| g.section_index) {
// no text -> do nothing
None => return,
// if cursor is at the end, position at FlexEnd so newly typed text does not take a frame to move into view
Some(1) => {
style.left = Val::Auto;
parent_style.justify_content = JustifyContent::FlexEnd;
return;
}
_ => (),
}

// if cursor is in the middle, we use FlexStart + `left` px for consistent behaviour when typing the middle
let child_size = child_node.size().x;
let parent_size = parent_node.size().x;

let Some(cursor_pos) = layout
.glyphs
.iter()
.find(|g| g.section_index == 1)
.map(|p| p.position.x)
else {
continue;
};

// glyph positions are not adjusted for scale factor so we do that here
let window_ref = match target_camera {
Some(target) => {
let Ok(camera) = cameras.get(target.0) else {
continue;
};

match camera.target {
RenderTarget::Window(window_ref) => Some(window_ref),
_ => None,
}
}
None => Some(WindowRef::Primary),
};

let scale_factor = match window_ref {
Some(window_ref) => {
let window = match window_ref {
WindowRef::Entity(w) => all_windows.get(w).ok(),
WindowRef::Primary => primary_window.get_single().ok(),
};

let Some(window) = window else {
continue;
};

window.scale_factor()
}
None => 1.0,
};
let cursor_pos = cursor_pos / scale_factor;

let box_pos = match style.left {
Val::Px(px) => -px,
_ => child_size - parent_size,
};

let relative_pos = cursor_pos - box_pos;

if relative_pos < 0.0 || relative_pos > parent_size {
let req_px = parent_size * 0.5 - cursor_pos;
let req_px = req_px.clamp(parent_size - child_size, 0.0);
style.left = Val::Px(req_px);
parent_style.justify_content = JustifyContent::FlexStart;
}
}
}

fn create(
mut commands: Commands,
query: Query<
Expand Down

0 comments on commit b4f7622

Please sign in to comment.