avm2: Store the last-hovered or currently-hovered object on the event that notifies the clip that the hover state has changed.

This commit is contained in:
David Wendt 2021-12-07 19:12:42 -05:00 committed by Mike Welsh
parent f69206aaa2
commit d0ef15503c
6 changed files with 64 additions and 17 deletions

View File

@ -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(),

View File

@ -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,
};

View File

@ -251,3 +251,17 @@ pub trait TInteractiveObject<'gc>:
self.event_dispatch(context, event)
}
}
impl<'gc> InteractiveObject<'gc> {
pub fn ptr_eq<T: TInteractiveObject<'gc>>(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> {}

View File

@ -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")),

View File

@ -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<InteractiveObject<'gc>>,
},
/// Mouse moved into a display object.
RollOver {
from: Option<InteractiveObject<'gc>>,
},
/// 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"),

View File

@ -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;
}