Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion crates/bevy_picking/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,8 @@ pub struct Press {
pub button: PointerButton,
/// Information about the picking intersection.
pub hit: HitData,
/// Number of consecutive presses, starting at `1`.
pub count: u8,
}

/// Fires when a pointer button is released over the [target entity](EntityEvent::event_target).
Expand Down Expand Up @@ -920,19 +922,28 @@ pub fn pointer_events(
match action {
PointerAction::Press(button) => {
let state = pointer_state.get_mut(pointer_id, button);
state
.clicking
.retain(|_, (last_click, _)| now - *last_click <= MULTI_CLICK_DURATION);

// If it's a press, emit a Pressed event and mark the hovered entities as pressed
for (hovered_entity, hit) in hover_map
.get(&pointer_id)
.iter()
.flat_map(|h| h.iter().map(|(entity, data)| (*entity, data.clone())))
{
let count = state
.clicking
.get(&hovered_entity)
.map_or(1, |(_, count)| count.saturating_add(1));
state.clicking.insert(hovered_entity, (now, count));
let pressed_event = Pointer::new(
pointer_id,
location.clone(),
Press {
button,
hit: hit.clone(),
count,
},
hovered_entity,
);
Expand Down Expand Up @@ -961,7 +972,7 @@ pub fn pointer_events(
let count = state
.clicking
.get(&hovered_entity)
.map_or(1, |(_, count)| count.saturating_add(1));
.map_or(1, |(_, count)| *count);
state.clicking.insert(hovered_entity, (now, count));
let click_event = Pointer::new(
pointer_id,
Expand Down
71 changes: 12 additions & 59 deletions crates/bevy_ui_widgets/src/text_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use bevy_input_focus::{
FocusCause, FocusGained, FocusLost, FocusedInput, InputFocus, InputFocusSystems,
};
use bevy_math::Vec2;
use bevy_picking::events::{Click, Drag, Pointer, Press, Release};
use bevy_picking::events::{Drag, Pointer, Press, Release};
use bevy_picking::pointer::PointerButton;
use bevy_text::{EditableText, PreeditCursor, TextEdit};
use bevy_ui::widget::{scroll_editable_text, update_editable_text_layout, TextScroll};
Expand Down Expand Up @@ -190,69 +190,23 @@ fn on_pointer_press(
return;
};

editable_text
.pending_edits
.push(if keys.pressed(Key::Shift) {
TextEdit::ShiftClickExtension
} else {
TextEdit::MoveToPoint
}(local_pos));

input_focus.set(press.entity, FocusCause::Pressed);

press.propagate(false);
}

/// System that processes pointer click events into text edit actions for [`EditableText`] widgets.
///
/// `Click`s follow `Press`, so multi-click `TextEdit`s are queued after those from the corresponding `Press`.
///
/// Note that this does not immediately apply the edits; they are queued up in [`EditableText::pending_edits`],
/// and then applied later by the [`apply_text_edits`](`bevy_text::apply_text_edits`) system.
fn on_pointer_click(
mut click: On<Pointer<Click>>,
mut text_input_query: Query<(
&mut EditableText,
&ComputedNode,
&ComputedUiRenderTargetInfo,
&UiGlobalTransform,
&TextScroll,
)>,
ui_scale: Res<UiScale>,
) {
if click.button != PointerButton::Primary {
return;
}

let Ok((mut editable_text, node, target, transform, text_scroll)) =
text_input_query.get_mut(click.entity)
else {
return;
};

if editable_text.is_composing() {
// The IME is active; all input needs to be routed there, including pointer multi-clicks.
return;
}

let Some(local_pos) = transform.try_inverse().map(|inverse| {
inverse
.transform_point2(click.pointer_location.position * target.scale_factor() / ui_scale.0)
- node.content_box().min
+ text_scroll.0
}) else {
return;
};

match click.count {
match press.count {
1 => {
// No special processing required for single clicks. Presses set the cursor position and are handled by `on_pointer_press`.
editable_text
.pending_edits
.push(if keys.pressed(Key::Shift) {
TextEdit::ShiftClickExtension
} else {
TextEdit::MoveToPoint
}(local_pos));
}
2 => editable_text.queue_edit(TextEdit::SelectWordAtPoint(local_pos)),
_ => editable_text.queue_edit(TextEdit::SelectAll),
}

click.propagate(false);
input_focus.set(press.entity, FocusCause::Pressed);

press.propagate(false);
}

/// System that processes pointer drag events into text edit actions for [`EditableText`] widgets.
Expand Down Expand Up @@ -540,7 +494,6 @@ impl Plugin for EditableTextInputPlugin {
.add_observer(on_pointer_press)
.add_observer(on_focus_lost_clear_ime)
.add_observer(on_focus_select_all)
.add_observer(on_pointer_click)
.add_systems(
PreUpdate,
(
Expand Down
Loading