Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for diffrent mouse buttons in UI buttons #389

Closed
wants to merge 10 commits into from
6 changes: 3 additions & 3 deletions crates/bevy_input/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ use std::hash::Hash;

/// A "press-able" input of type `T`
pub struct Input<T> {
pressed: HashSet<T>,
just_pressed: HashSet<T>,
just_released: HashSet<T>,
pub pressed: HashSet<T>,
pub just_pressed: HashSet<T>,
pub just_released: HashSet<T>,
TheRawMeatball marked this conversation as resolved.
Show resolved Hide resolved
}

impl<T> Default for Input<T> {
Expand Down
11 changes: 11 additions & 0 deletions crates/bevy_input/src/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,17 @@ pub enum MouseButton {
Other(u8),
}

impl Into<u16> for MouseButton {
fn into(self) -> u16 {
match self {
MouseButton::Left => 0,
MouseButton::Right => 1,
MouseButton::Middle => 2,
MouseButton::Other(i) => u16::from(i),
}
}
}

/// A mouse motion event
#[derive(Debug, Clone)]
pub struct MouseMotion {
Expand Down
80 changes: 67 additions & 13 deletions crates/bevy_ui/src/focus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,44 @@ use bevy_window::CursorMoved;

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Interaction {
Clicked,
Clicked(MouseFlags),
Hovered,
None,
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct MouseFlags(u16);

impl MouseFlags {
pub fn check(self, button: MouseButton) -> bool {
let i: u16 = button.into();
((self.0 << i) >> 15) > 0
}

pub fn build(button: &MouseButton) -> Self {
button.clone().into()
}

pub fn remove(&mut self, button: &MouseButton) {
let i: u16 = button.clone().into();
let mask = !((u16::MAX << 15) >> i);
self.0 &= mask;
}

pub fn add(&mut self, button: &MouseButton) {
let i: u16 = button.clone().into();
let mask = (u16::MAX << 15) >> i;
self.0 |= mask;
}
}

impl From<MouseButton> for MouseFlags {
fn from(button: MouseButton) -> Self {
let i: u16 = button.into();
MouseFlags((u16::MAX << 15) >> i)
}
}

impl Default for Interaction {
fn default() -> Self {
Interaction::None
Expand Down Expand Up @@ -55,17 +88,21 @@ pub fn ui_focus_system(
state.cursor_position = cursor_moved.position;
}

if mouse_button_input.just_released(MouseButton::Left) {
for (_entity, _node, _transform, interaction, _focus_policy) in &mut node_query.iter() {
if let Some(mut interaction) = interaction {
if *interaction == Interaction::Clicked {
*interaction = Interaction::None;
for (_entity, _node, _transform, interaction, _focus_policy) in &mut node_query.iter() {
if let Some(mut interaction) = interaction {
for released in &mouse_button_input.just_released {
if let Interaction::Clicked(mut flags) = *interaction {
flags.remove(released);
*interaction = Interaction::Clicked(flags);
}
}

if let Interaction::Clicked(MouseFlags(0)) = *interaction {
*interaction = Interaction::None;
}
}
}

let mouse_clicked = mouse_button_input.just_pressed(MouseButton::Left);
let mut hovered_entity = None;

{
Expand Down Expand Up @@ -97,13 +134,30 @@ pub fn ui_focus_system(
moused_over_z_sorted_nodes.sort_by_key(|(_, _, _, z)| -*z);
for (entity, focus_policy, interaction, _) in moused_over_z_sorted_nodes {
if let Some(mut interaction) = interaction {
if mouse_clicked {
// only consider nodes with ClickState "clickable"
if *interaction != Interaction::Clicked {
*interaction = Interaction::Clicked;
}
} else if *interaction == Interaction::None {
// Build bitflags out of hashset
let new_flags = mouse_button_input.just_pressed.iter().fold(
MouseFlags(0),
|mut flags, button| {
flags.add(button);
flags
},
);

let old_flags =
mouse_button_input
.pressed
.iter()
.fold(MouseFlags(0), |mut flags, button| {
flags.add(button);
flags
});

if old_flags.0 == 0
// nothing is clicked
{
*interaction = Interaction::Hovered;
} else if new_flags.0 != 0 {
*interaction = Interaction::Clicked(old_flags)
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ pub mod prelude {
entity::*,
node::*,
widget::{Button, Text},
Anchors, Interaction, Margins,
Anchors, Interaction, Margins, MouseFlags,
};
}

Expand Down
16 changes: 13 additions & 3 deletions examples/ui/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,18 @@ fn button_system(
for (_button, interaction, mut material, children) in &mut interaction_query.iter() {
let mut text = text_query.get_mut::<Text>(children[0]).unwrap();
match *interaction {
Interaction::Clicked => {
text.value = "Press".to_string();
Interaction::Clicked(i) => {
let mut s = String::from("Pressing button(s)");
if i.check(MouseButton::Left) {
s.push_str(" Left");
}
if i.check(MouseButton::Right) {
s.push_str(" Right");
}
if i.check(MouseButton::Middle) {
s.push_str(" Middle");
}
text.value = s;
*material = button_materials.pressed;
}
Interaction::Hovered => {
Expand All @@ -66,7 +76,7 @@ fn setup(
.spawn(UiCameraComponents::default())
.spawn(ButtonComponents {
style: Style {
size: Size::new(Val::Px(150.0), Val::Px(65.0)),
size: Size::new(Val::Px(550.0), Val::Px(65.0)),
// center button
margin: Rect::all(Val::Auto),
// horizontally center child text
Expand Down