Skip to content

Commit

Permalink
Use Bevy's built-in scrolling
Browse files Browse the repository at this point in the history
  • Loading branch information
rparrett committed Jan 15, 2025
1 parent 4b7cec0 commit e11e44b
Showing 1 changed file with 15 additions and 74 deletions.
89 changes: 15 additions & 74 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@ use bevy::{
ecs::{event::EventCursor, system::SystemParam},
input::keyboard::{Key, KeyboardInput},
prelude::*,
render::camera::RenderTarget,
text::{LineBreak, TextLayoutInfo},
ui::FocusPolicy,
window::{PrimaryWindow, WindowRef},
};

/// A Bevy `Plugin` providing the systems and assets required to make a [`TextInput`] work.
Expand Down Expand Up @@ -472,40 +470,18 @@ fn update_value(

fn scroll_with_cursor(
mut inner_text_query: Query<
(
&TextLayoutInfo,
&mut Node,
&ComputedNode,
&Parent,
Option<&TargetCamera>,
),
(&TextLayoutInfo, &ComputedNode, &Parent),
(With<TextInputInner>, Changed<TextLayoutInfo>),
>,
mut style_query: Query<(&ComputedNode, &mut Node), Without<TextInputInner>>,
camera_query: Query<&Camera>,
window_query: Query<&Window>,
primary_window_query: Query<&Window, With<PrimaryWindow>>,
mut style_query: Query<(&ComputedNode, &mut ScrollPosition), Without<TextInputInner>>,
) {
for (layout, mut style, child_node, parent, target_camera) in inner_text_query.iter_mut() {
let Ok((parent_node, mut parent_style)) = style_query.get_mut(parent.get()) else {
for (layout, text_node, parent) in inner_text_query.iter_mut() {
let Ok((overflow_node, mut overflow_scroll)) = style_query.get_mut(parent.get()) else {
continue;
};

match layout.glyphs.last().map(|g| g.span_index) {
// no text -> do nothing
None => continue,
// 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;
continue;
}
_ => (),
}

// 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 text_size = text_node.size().x;
let overflow_size = overflow_node.size().x;

let Some(cursor_pos) = layout
.glyphs
Expand All @@ -516,50 +492,14 @@ fn scroll_with_cursor(
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) = camera_query.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) => window_query.get(w).ok(),
WindowRef::Primary => primary_window_query.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 box_pos = overflow_scroll.offset_x;
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;
if relative_pos < 0.0 || relative_pos > overflow_size {
let req_px = overflow_size * 0.5 - cursor_pos;
let req_px = req_px.clamp(overflow_size - text_size, 0.0);

overflow_scroll.offset_x = -req_px;
}
}
}
Expand Down Expand Up @@ -664,11 +604,12 @@ fn create(
))
.id();

// Workaround for clipping not working for Text nodes.
// See https://github.com/bevyengine/bevy/issues/12085
let overflow_container = commands
.spawn((
Node {
overflow: Overflow::clip(),
justify_content: JustifyContent::FlexEnd,
overflow: Overflow::scroll_x(),
max_width: Val::Percent(100.),
..default()
},
Expand Down

0 comments on commit e11e44b

Please sign in to comment.