From d0ef15503c2d2c1cc6f1261a394fbd750f1b82c3 Mon Sep 17 00:00:00 2001 From: David Wendt Date: Tue, 7 Dec 2021 19:12:42 -0500 Subject: [PATCH] avm2: Store the last-hovered or currently-hovered object on the event that notifies the clip that the hover state has changed. --- core/src/display_object/avm1_button.rs | 4 ++-- core/src/display_object/avm2_button.rs | 6 +++-- core/src/display_object/interactive.rs | 14 +++++++++++ core/src/display_object/movie_clip.rs | 4 ++-- core/src/events.rs | 32 +++++++++++++++++++------- core/src/player.rs | 21 ++++++++++++++--- 6 files changed, 64 insertions(+), 17 deletions(-) diff --git a/core/src/display_object/avm1_button.rs b/core/src/display_object/avm1_button.rs index c723fde12..1f6ca8286 100644 --- a/core/src/display_object/avm1_button.rs +++ b/core/src/display_object/avm1_button.rs @@ -503,12 +503,12 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> { ButtonActionCondition::OUT_DOWN_TO_IDLE, static_data.over_to_up_sound.as_ref(), ), - ClipEvent::RollOut => ( + ClipEvent::RollOut { .. } => ( ButtonState::Up, ButtonActionCondition::OVER_UP_TO_IDLE, static_data.over_to_up_sound.as_ref(), ), - ClipEvent::RollOver => ( + ClipEvent::RollOver { .. } => ( ButtonState::Over, ButtonActionCondition::IDLE_TO_OVER_UP, static_data.up_to_over_sound.as_ref(), diff --git a/core/src/display_object/avm2_button.rs b/core/src/display_object/avm2_button.rs index 1dc6e73fd..6e55194a4 100644 --- a/core/src/display_object/avm2_button.rs +++ b/core/src/display_object/avm2_button.rs @@ -792,8 +792,10 @@ impl<'gc> TInteractiveObject<'gc> for Avm2Button<'gc> { ClipEvent::Press => (ButtonState::Down, static_data.over_to_down_sound.as_ref()), ClipEvent::Release => (ButtonState::Over, static_data.down_to_over_sound.as_ref()), ClipEvent::ReleaseOutside => (ButtonState::Up, static_data.over_to_up_sound.as_ref()), - ClipEvent::RollOut => (ButtonState::Up, static_data.over_to_up_sound.as_ref()), - ClipEvent::RollOver => (ButtonState::Over, static_data.up_to_over_sound.as_ref()), + ClipEvent::RollOut { .. } => (ButtonState::Up, static_data.over_to_up_sound.as_ref()), + ClipEvent::RollOver { .. } => { + (ButtonState::Over, static_data.up_to_over_sound.as_ref()) + } _ => return ClipEventResult::NotHandled, }; diff --git a/core/src/display_object/interactive.rs b/core/src/display_object/interactive.rs index d621283ff..3c859064c 100644 --- a/core/src/display_object/interactive.rs +++ b/core/src/display_object/interactive.rs @@ -251,3 +251,17 @@ pub trait TInteractiveObject<'gc>: self.event_dispatch(context, event) } } + +impl<'gc> InteractiveObject<'gc> { + pub fn ptr_eq>(a: T, b: T) -> bool { + a.as_displayobject().as_ptr() == b.as_displayobject().as_ptr() + } +} + +impl<'gc> PartialEq for InteractiveObject<'gc> { + fn eq(&self, other: &Self) -> bool { + InteractiveObject::ptr_eq(*self, *other) + } +} + +impl<'gc> Eq for InteractiveObject<'gc> {} diff --git a/core/src/display_object/movie_clip.rs b/core/src/display_object/movie_clip.rs index 5abd60752..75e292ba5 100644 --- a/core/src/display_object/movie_clip.rs +++ b/core/src/display_object/movie_clip.rs @@ -2141,8 +2141,8 @@ impl<'gc> TInteractiveObject<'gc> for MovieClip<'gc> { event: ClipEvent, ) -> ClipEventResult { let frame_name = match event { - ClipEvent::RollOut | ClipEvent::ReleaseOutside => Some(WStr::from_units(b"_up")), - ClipEvent::RollOver | ClipEvent::Release | ClipEvent::DragOut => { + ClipEvent::RollOut { .. } | ClipEvent::ReleaseOutside => Some(WStr::from_units(b"_up")), + ClipEvent::RollOver { .. } | ClipEvent::Release | ClipEvent::DragOut => { Some(WStr::from_units(b"_over")) } ClipEvent::Press | ClipEvent::DragOver => Some(WStr::from_units(b"_down")), diff --git a/core/src/events.rs b/core/src/events.rs index f47ae8d76..cd0ad397e 100644 --- a/core/src/events.rs +++ b/core/src/events.rs @@ -1,3 +1,4 @@ +use crate::display_object::InteractiveObject; use swf::ClipEventFlag; #[derive(Debug)] @@ -73,7 +74,7 @@ pub enum ClipEventResult { /// kinds of scripts; with AVM2 versions of those events optionally providing /// capture and bubbling phases. #[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum ClipEvent { +pub enum ClipEvent<'gc> { Construct, Data, DragOut, @@ -111,8 +112,23 @@ pub enum ClipEvent { /// AVM1 and AVM2. The target of this event is determined by the position /// of the mouse cursor. Press, - RollOut, - RollOver, + + /// Mouse moved out of a display object. + /// + /// This is a targeted equivalent to `MouseMove` and is available in both + /// AVM1 and AVM2. Confusingly, it covers both `mouseOut` and `rollOut`, + /// the difference being that the former bubbles, while the latter only + /// fires when the cursor has left the parent *and* it's children. + /// + /// The parameter `to` is the current object that is now under the cursor. + RollOut { + to: Option>, + }, + + /// Mouse moved into a display object. + RollOver { + from: Option>, + }, /// Mouse button was released inside a previously-pressed display object. /// @@ -130,7 +146,7 @@ pub enum ClipEvent { Unload, } -impl ClipEvent { +impl<'gc> ClipEvent<'gc> { /// Method names for button event handles. pub const BUTTON_EVENT_METHODS: [&'static str; 7] = [ "onDragOver", @@ -170,8 +186,8 @@ impl ClipEvent { ClipEvent::MouseMove => ClipEventFlag::MOUSE_MOVE, ClipEvent::MouseUp | ClipEvent::MouseUpInside => ClipEventFlag::MOUSE_UP, ClipEvent::Press => ClipEventFlag::PRESS, - ClipEvent::RollOut => ClipEventFlag::ROLL_OUT, - ClipEvent::RollOver => ClipEventFlag::ROLL_OVER, + ClipEvent::RollOut { .. } => ClipEventFlag::ROLL_OUT, + ClipEvent::RollOver { .. } => ClipEventFlag::ROLL_OVER, ClipEvent::Release => ClipEventFlag::RELEASE, ClipEvent::ReleaseOutside => ClipEventFlag::RELEASE_OUTSIDE, ClipEvent::Unload => ClipEventFlag::UNLOAD, @@ -218,8 +234,8 @@ impl ClipEvent { ClipEvent::MouseMove => Some("onMouseMove"), ClipEvent::MouseUp => Some("onMouseUp"), ClipEvent::Press => Some("onPress"), - ClipEvent::RollOut => Some("onRollOut"), - ClipEvent::RollOver => Some("onRollOver"), + ClipEvent::RollOut { .. } => Some("onRollOut"), + ClipEvent::RollOver { .. } => Some("onRollOver"), ClipEvent::Release => Some("onRelease"), ClipEvent::ReleaseOutside => Some("onReleaseOutside"), ClipEvent::Unload => Some("onUnload"), diff --git a/core/src/player.rs b/core/src/player.rs index d50440f13..fb7a03c0d 100644 --- a/core/src/player.rs +++ b/core/src/player.rs @@ -1152,12 +1152,22 @@ impl Player { // The mouse button is up, so fire rollover states for the object we are hovering over. // Rolled out of the previous object. if let Some(cur_over_object) = cur_over_object { - events.push((cur_over_object, ClipEvent::RollOut)); + events.push(( + cur_over_object, + ClipEvent::RollOut { + to: new_over_object.and_then(|d| d.as_interactive()), + }, + )); } // Rolled over the new object. if let Some(new_over_object) = new_over_object { new_cursor = new_over_object.mouse_cursor(context); - events.push((new_over_object, ClipEvent::RollOver)); + events.push(( + new_over_object, + ClipEvent::RollOver { + from: cur_over_object.and_then(|d| d.as_interactive()), + }, + )); } else { new_cursor = MouseCursor::Arrow; } @@ -1203,7 +1213,12 @@ impl Player { // The new object is rolled over immediately. if let Some(over_object) = context.mouse_over_object { new_cursor = over_object.mouse_cursor(context); - events.push((over_object, ClipEvent::RollOver)); + events.push(( + over_object, + ClipEvent::RollOver { + from: cur_over_object.and_then(|d| d.as_interactive()), + }, + )); } else { new_cursor = MouseCursor::Arrow; }