Skip to content

Commit

Permalink
Use workflows for mouse interactions (#236)
Browse files Browse the repository at this point in the history
Signed-off-by: Michael X. Grey <[email protected]>
  • Loading branch information
mxgrey authored Aug 29, 2024
1 parent 5bbbc0c commit f4bed77
Show file tree
Hide file tree
Showing 52 changed files with 4,934 additions and 3,139 deletions.
47 changes: 23 additions & 24 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rmf_site_editor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pathdiff = "*"
tera = "1.19.1"
ehttp = { version = "0.4", features = ["native-async"] }
nalgebra = "0.32.5"
anyhow = "*"

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
clap = { version = "4.0.10", features = ["color", "derive", "help", "usage", "suggestions"] }
Expand Down
65 changes: 38 additions & 27 deletions rmf_site_editor/src/interaction/anchor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ use crate::{
};
use bevy::prelude::*;

/// Use this resource to indicate whether anchors should be constantly highlighted.
/// This is used during anchor selection modes to make it easier for users to know
/// where selectable anchors are.
#[derive(Clone, Copy, Debug, Resource)]
pub struct HighlightAnchors(pub bool);

#[derive(Component, Debug, Clone, Copy)]
pub struct AnchorVisualization {
pub body: Entity,
Expand All @@ -37,6 +43,7 @@ pub fn add_anchor_visual_cues(
>,
categories: Query<&Category>,
site_assets: Res<SiteAssets>,
highlight: Res<HighlightAnchors>,
) {
for (e, parent, subordinate, anchor) in &new_anchors {
let body_mesh = match categories.get(parent.get()).unwrap() {
Expand Down Expand Up @@ -65,12 +72,29 @@ pub fn add_anchor_visual_cues(
.insert(OutlineVisualization::Anchor { body })
.add_child(body);

// 3D anchors should always be visible with arrow cue meshes
if anchor.is_3D() {
entity_commands.insert(VisualCue::outline());
let cue = if anchor.is_3D() {
// 3D anchors should always be visible with arrow cue meshes
VisualCue::outline()
} else {
entity_commands.insert(VisualCue::outline().irregular());
}
let mut cue = VisualCue::outline().irregular();
cue.xray.set_always(highlight.0);
cue
};

entity_commands.insert(cue);
}
}

pub fn on_highlight_anchors_change(
highlight: Res<HighlightAnchors>,
mut anchor_visual_cues: Query<&mut VisualCue, With<Anchor>>,
) {
if !highlight.is_changed() {
return;
}

for mut cue in &mut anchor_visual_cues {
cue.xray.set_always(highlight.0);
}
}

Expand Down Expand Up @@ -110,12 +134,12 @@ pub fn update_anchor_proximity_xray(
}

let p_c = match intersect_ground_params.ground_plane_intersection() {
Some(p) => p,
Some(p) => p.translation,
None => return,
};

for (anchor_tf, mut cue) in &mut anchors {
// TODO(MXG): Make the proximity range configurable
// TODO(@mxgrey): Make the proximity range configurable
let proximity = {
// We make the xray effect a little "sticky" so that there isn't an
// ugly flicker for anchors that are right at the edge of the
Expand Down Expand Up @@ -156,22 +180,6 @@ pub fn update_unassigned_anchor_cues(
}
}

pub fn update_anchor_cues_for_mode(
mode: Res<InteractionMode>,
mut anchors: Query<&mut VisualCue, With<Anchor>>,
) {
if !mode.is_changed() {
return;
}

let anchor_always_visible = mode.is_selecting_anchor();
for mut cue in &mut anchors {
if cue.xray.always() != anchor_always_visible {
cue.xray.set_always(anchor_always_visible);
}
}
}

pub fn update_anchor_visual_cues(
mut commands: Commands,
mut anchors: Query<
Expand All @@ -191,10 +199,11 @@ pub fn update_anchor_visual_cues(
mut visibility: Query<&mut Visibility>,
mut materials: Query<&mut Handle<StandardMaterial>>,
deps: Query<&Dependents>,
cursor: Res<Cursor>,
mut cursor: ResMut<Cursor>,
site_assets: Res<SiteAssets>,
interaction_assets: Res<InteractionAssets>,
debug_mode: Option<Res<DebugMode>>,
gizmo_blockers: Res<GizmoBlockers>,
) {
for (
a,
Expand Down Expand Up @@ -235,8 +244,10 @@ pub fn update_anchor_visual_cues(
.set_support_hovered(!hovered.support_hovering.is_empty());
}

if hovered.is_hovered {
set_visibility(cursor.frame, &mut visibility, false);
if hovered.is_hovered && !gizmo_blockers.blocking() {
cursor.add_blocker(a, &mut visibility);
} else {
cursor.remove_blocker(a, &mut visibility);
}

if hovered.cue() && selected.cue() {
Expand Down Expand Up @@ -303,7 +314,7 @@ pub fn update_anchor_visual_cues(
}

// NOTE(MXG): Currently only anchors ever have support cues, so we filter down
// to entities with AnchorVisualCues. We will need to broaden that if any other
// to entities with AnchorVisualization. We will need to broaden that if any other
// visual cue types ever have a supporting role.
pub fn remove_deleted_supports_from_visual_cues(
mut hovered: Query<&mut Hovered, With<AnchorVisualization>>,
Expand Down
13 changes: 8 additions & 5 deletions rmf_site_editor/src/interaction/assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,14 @@ impl InteractionAssets {

commands.entity(drag_parent).with_children(|parent| {
for (polyline, material) in &self.centimeter_finite_grid {
parent.spawn(PolylineBundle {
polyline: polyline.clone(),
material: material.clone(),
..default()
});
parent.spawn((
PolylineBundle {
polyline: polyline.clone(),
material: material.clone(),
..default()
},
DisableXray,
));
}
});

Expand Down
15 changes: 5 additions & 10 deletions rmf_site_editor/src/interaction/camera_controls/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use super::{
CameraCommandType, CameraControls, ProjectionMode, MAX_FOV, MAX_SCALE, MIN_FOV, MIN_SCALE,
};
use crate::interaction::SiteRaycastSet;
use bevy::input::mouse::MouseWheel;
use bevy::input::mouse::{MouseScrollUnit, MouseWheel};
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use bevy_mod_raycast::deferred::RaycastSource;
Expand Down Expand Up @@ -92,15 +92,10 @@ pub fn update_cursor_command(
// Scroll input
let mut scroll_motion = 0.0;
for ev in mouse_wheel.read() {
#[cfg(not(target_arch = "wasm32"))]
{
scroll_motion += ev.y;
}
#[cfg(target_arch = "wasm32")]
{
// scrolling in wasm is a different beast
scroll_motion += 0.4 * ev.y / ev.y.abs();
}
scroll_motion += match ev.unit {
MouseScrollUnit::Line => ev.y,
MouseScrollUnit::Pixel => ev.y / 100.0,
};
}

// Command type, return if inactive
Expand Down
8 changes: 7 additions & 1 deletion rmf_site_editor/src/interaction/camera_controls/keyboard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,20 @@ pub fn update_keyboard_command(

// Set camera selection as orbit center, discard once orbit operation complete
let camera_selection = match keyboard_command.camera_selection {
Some(camera_selection) => camera_selection,
Some(camera_selection) => Some(camera_selection),
None => get_camera_selected_point(
&camera,
&camera_global_transform,
uncovered_window_area,
immediate_raycast,
),
};

let Some(camera_selection) = camera_selection else {
warn!("Point could not be calculated for camera");
return;
};

if command_type == CameraCommandType::Orbit {
camera_controls.orbit_center = Some(camera_selection);
}
Expand Down
13 changes: 6 additions & 7 deletions rmf_site_editor/src/interaction/camera_controls/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,11 @@ pub fn get_camera_selected_point(
camera_global_transform: &GlobalTransform,
user_camera_display: Res<UserCameraDisplay>,
mut immediate_raycast: Raycast,
) -> Vec3 {
) -> Option<Vec3> {
// Assume that the camera spans the full window, covered by egui panels
let available_viewport_center = user_camera_display.region.center();
let camera_ray = camera
.viewport_to_world(camera_global_transform, available_viewport_center)
.expect("Active camera does not have a valid ray from center of its viewport");
let camera_ray =
camera.viewport_to_world(camera_global_transform, available_viewport_center)?;
let camera_ray = Ray3d::new(camera_ray.origin, camera_ray.direction);
let raycast_setting = RaycastSettings::default()
.always_early_exit()
Expand All @@ -89,13 +88,13 @@ pub fn get_camera_selected_point(
let intersections = immediate_raycast.cast_ray(camera_ray, &raycast_setting);
if intersections.len() > 0 {
let (_, intersection_data) = &intersections[0];
return intersection_data.position();
return Some(intersection_data.position());
} else {
return get_groundplane_else_default_selection(
return Some(get_groundplane_else_default_selection(
camera_ray.origin(),
camera_ray.direction(),
camera_ray.direction(),
);
));
}
}

Expand Down
Loading

0 comments on commit f4bed77

Please sign in to comment.