bevy_trackball 0.15.0

Coherent virtual trackball controller/camera plugin for Bevy
Documentation
use bevy::{
	input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel},
	prelude::*,
	window::{CursorGrabMode, CursorIcon, CursorOptions, SystemCursorIcon},
};
use trackball::{
	Image,
	nalgebra::{Point2, Point3},
};

use super::{TrackballCamera, TrackballController, TrackballMessage};

#[allow(clippy::too_many_arguments)]
#[allow(clippy::too_many_lines)]
pub fn mouse(
	commands: &mut Commands,
	group: Entity,
	trackball_events: &mut MessageWriter<TrackballMessage>,
	trackball: &TrackballCamera,
	controller: &mut TrackballController,
	window_id: Entity,
	window: &Window,
	cursor_options: &mut CursorOptions,
	mouse_input: &Res<ButtonInput<MouseButton>>,
	mut delta_events: MessageReader<MouseMotion>,
	mut mouse_events: MessageReader<CursorMoved>,
	mut wheel_events: MessageReader<MouseWheel>,
	zat: f32,
	upp: f32,
	min: Vec2,
	max: Vec2,
	w: f32,
) {
	let pos = Point2::from(window.cursor_position().map_or(max * 0.5, |pos| pos - min));
	let max = max.into();
	let just_pressed_button =
		|button: Option<MouseButton>| button.is_some_and(|button| mouse_input.just_pressed(button));
	let just_released_button = |button: Option<MouseButton>| {
		button.is_some_and(|button| mouse_input.just_released(button))
	};
	if just_pressed_button(controller.input.first_button) {
		controller.first.capture(trackball.frame.yaw_axis());
		cursor_options.grab_mode = CursorGrabMode::Locked;
		cursor_options.visible = false;
	}
	if just_released_button(controller.input.first_button) {
		controller.first.discard();
		cursor_options.grab_mode = CursorGrabMode::None;
		cursor_options.visible = true;
	}
	for delta_event in delta_events.read() {
		if controller.first.enabled()
			&& let Some((pitch, yaw, yaw_axis)) =
				controller.first.compute(&(-delta_event.delta).into(), &max)
		{
			let pitch = pitch * controller.input.first_mouse_transmission;
			let yaw = yaw * controller.input.first_mouse_transmission;
			trackball_events.write(TrackballMessage::first(group, pitch, yaw, *yaw_axis));
		}
	}
	if just_pressed_button(controller.input.orbit_button) {
		controller.touch.compute(None, pos, 0);
		controller.orbit.compute(&pos, &max);
		commands
			.entity(window_id)
			.insert(CursorIcon::from(SystemCursorIcon::Pointer));
	}
	if just_released_button(controller.input.orbit_button) {
		if let Some((_num, pos)) = controller.touch.discard(None)
			&& controller.input.focus
		{
			let (pos, _max) = Image::transform_pos_and_max_wrt_max(&pos, &max);
			let vec = pos.coords.scale(upp).push(0.0);
			trackball_events.write(TrackballMessage::slide(group, vec));
		}
		controller.orbit.discard();
		commands
			.entity(window_id)
			.insert(CursorIcon::from(SystemCursorIcon::Default));
	}
	if just_pressed_button(controller.input.slide_button) {
		controller.slide.compute(pos);
		commands
			.entity(window_id)
			.insert(CursorIcon::from(SystemCursorIcon::Move));
	}
	if just_released_button(controller.input.slide_button) {
		controller.slide.discard();
		commands
			.entity(window_id)
			.insert(CursorIcon::from(SystemCursorIcon::Default));
	}
	for mouse_event in mouse_events.read() {
		let pos = mouse_event.position - min;
		if controller
			.input
			.orbit_button
			.is_some_and(|button| mouse_input.pressed(button))
			&& let Some((_num, pos, _rot, _rat)) = controller.touch.compute(None, pos.into(), 0)
			&& let Some(rot) = controller.orbit.compute(&pos, &max)
		{
			let rot = rot.powf(controller.input.orbit_mouse_transmission);
			trackball_events.write(TrackballMessage::orbit(group, rot, Point3::origin()));
		}
		if controller
			.input
			.slide_button
			.is_some_and(|button| mouse_input.pressed(button))
			&& let Some(vec) = controller
				.slide
				.compute(pos.into())
				.map(|vec| Image::transform_vec(&vec))
		{
			let vec = vec.scale(upp).push(0.0) * controller.input.slide_mouse_transmission;
			trackball_events.write(TrackballMessage::slide(group, vec));
		}
	}
	for &wheel_event in wheel_events.read() {
		let num = match wheel_event.unit {
			MouseScrollUnit::Line => {
				let denominator = controller.input.wheel_unit.denominator(w);
				controller.scale.set_denominator(denominator);
				wheel_event.y
			}
			MouseScrollUnit::Pixel => {
				controller.scale.set_denominator(zat);
				upp * wheel_event.y
			}
		} * controller.input.scale_wheel_transmission;
		let (pos, _max) = Image::transform_pos_and_max_wrt_max(&pos, &max);
		trackball_events.write(TrackballMessage::scale(
			group,
			controller.scale.compute(num),
			pos.coords.scale(upp).push(0.0).into(),
		));
	}
}