1use bevy::prelude::*;
2use bevy_rapier3d::prelude::*;
3
4use smallvec::SmallVec;
5
6mod ui_3d;
7
8pub use ui_3d::{Interaction3d, PluginConfig};
9
10#[derive(Component, Default)]
11pub struct Ui3dElement;
12
13#[derive(Bundle, Default)]
16pub struct Ui3dElementBundle {
17 pub ui_element: Ui3dElement,
18 pub interaction: Interaction3d,
19 pub collider: Collider,
20}
21
22#[derive(Default, Resource)]
23pub(crate) struct UiState {
24 ui_3d_entities_to_reset: SmallVec<[Entity; 1]>,
26}
27
28#[derive(Default)]
29pub struct Ui3dPlugin {
30 pub config: PluginConfig,
31}
32
33impl Plugin for Ui3dPlugin {
34 fn build(&self, app: &mut App) {
35 app.init_resource::<UiState>()
36 .insert_resource(self.config.clone());
37
38 if !app.is_plugin_added::<RapierPhysicsPlugin>() {
39 app.add_plugins(RapierPhysicsPlugin::<NoUserData>::default());
40 }
41
42 app.add_systems(
43 PreUpdate,
44 (absorb_bevy_ui_inputs).after(bevy::ui::ui_focus_system),
45 );
46
47 app.add_systems(Update, ui_3d::interaction_system);
48 }
49}
50
51fn absorb_bevy_ui_inputs(
52 mut mouse: ResMut<Input<MouseButton>>,
53 interaction_query: Query<&Interaction, (With<Node>, Changed<Interaction>)>,
54) {
55 let event_absorbed_by_ui = interaction_query
56 .iter()
57 .any(|i| matches!(i, Interaction::Pressed | Interaction::Hovered));
58
59 if event_absorbed_by_ui {
60 mouse.reset_all();
61 }
62}