core: Add a method to fire common `InteractiveObject` events into AVM2.

This commit is contained in:
David Wendt 2021-12-04 14:50:10 -05:00 committed by Mike Welsh
parent 18b8b227a1
commit 6d02248ea5
5 changed files with 56 additions and 6 deletions

View File

@ -805,6 +805,8 @@ impl<'gc> TInteractiveObject<'gc> for Avm2Button<'gc> {
self.set_state(context, new_state); self.set_state(context, new_state);
} }
self.event_dispatch_to_avm2(context, event);
handled handled
} }
} }

View File

@ -1821,7 +1821,7 @@ impl<'gc> TInteractiveObject<'gc> for EditText<'gc> {
fn event_dispatch( fn event_dispatch(
self, self,
context: &mut UpdateContext<'_, 'gc, '_>, context: &mut UpdateContext<'_, 'gc, '_>,
_event: ClipEvent, event: ClipEvent,
) -> ClipEventResult { ) -> ClipEventResult {
let tracker = context.focus_tracker; let tracker = context.focus_tracker;
tracker.set(Some(self.into()), context); tracker.set(Some(self.into()), context);
@ -1835,6 +1835,8 @@ impl<'gc> TInteractiveObject<'gc> for EditText<'gc> {
Some(TextSelection::for_position(self.text_length())); Some(TextSelection::for_position(self.text_length()));
} }
self.event_dispatch_to_avm2(context, event);
ClipEventResult::Handled ClipEventResult::Handled
} }
} }

View File

@ -1,6 +1,6 @@
//! Interactive object enumtrait //! Interactive object enumtrait
use crate::avm2::Value; use crate::avm2::{Avm2, Event as Avm2Event, EventData as Avm2EventData, Value as Avm2Value};
use crate::context::UpdateContext; use crate::context::UpdateContext;
use crate::display_object::avm1_button::Avm1Button; use crate::display_object::avm1_button::Avm1Button;
use crate::display_object::avm2_button::Avm2Button; use crate::display_object::avm2_button::Avm2Button;
@ -36,7 +36,7 @@ bitflags! {
pub struct InteractiveObjectBase<'gc> { pub struct InteractiveObjectBase<'gc> {
pub base: DisplayObjectBase<'gc>, pub base: DisplayObjectBase<'gc>,
flags: InteractiveObjectFlags, flags: InteractiveObjectFlags,
context_menu: Value<'gc>, context_menu: Avm2Value<'gc>,
} }
impl<'gc> Default for InteractiveObjectBase<'gc> { impl<'gc> Default for InteractiveObjectBase<'gc> {
@ -44,7 +44,7 @@ impl<'gc> Default for InteractiveObjectBase<'gc> {
Self { Self {
base: Default::default(), base: Default::default(),
flags: InteractiveObjectFlags::MOUSE_ENABLED, flags: InteractiveObjectFlags::MOUSE_ENABLED,
context_menu: Value::Null, context_menu: Avm2Value::Null,
} }
} }
} }
@ -97,11 +97,11 @@ pub trait TInteractiveObject<'gc>:
.set(InteractiveObjectFlags::DOUBLE_CLICK_ENABLED, value) .set(InteractiveObjectFlags::DOUBLE_CLICK_ENABLED, value)
} }
fn context_menu(self) -> Value<'gc> { fn context_menu(self) -> Avm2Value<'gc> {
self.ibase().context_menu self.ibase().context_menu
} }
fn set_context_menu(self, mc: MutationContext<'gc, '_>, value: Value<'gc>) { fn set_context_menu(self, mc: MutationContext<'gc, '_>, value: Avm2Value<'gc>) {
self.ibase_mut(mc).context_menu = value; self.ibase_mut(mc).context_menu = value;
} }
@ -150,6 +150,48 @@ pub trait TInteractiveObject<'gc>:
_event: ClipEvent, _event: ClipEvent,
) -> ClipEventResult; ) -> ClipEventResult;
/// Convert the clip event into an AVM2 event and dispatch it into the
/// AVM2 side of this object.
///
/// This is only intended to be called for events defined by
/// `InteractiveObject` itself. Display object impls that have their own
/// event types should dispatch them in `event_dispatch`.
fn event_dispatch_to_avm2(self, context: &mut UpdateContext<'_, 'gc, '_>, event: ClipEvent) {
let target = if let Avm2Value::Object(target) = self.as_displayobject().object2() {
target
} else {
return;
};
match event {
ClipEvent::MouseDown => {
let mut avm2_event = Avm2Event::new(
"mouseDown",
Avm2EventData::mouse_event(context, self.as_displayobject(), None, 0),
);
avm2_event.set_bubbles(true);
if let Err(e) = Avm2::dispatch_event(context, avm2_event, target) {
log::error!("Got error when dispatching {:?} to AVM2: {}", event, e);
}
}
ClipEvent::MouseUp => {
let mut avm2_event = Avm2Event::new(
"mouseUp",
Avm2EventData::mouse_event(context, self.as_displayobject(), None, 0),
);
avm2_event.set_bubbles(true);
if let Err(e) = Avm2::dispatch_event(context, avm2_event, target) {
log::error!("Got error when dispatching {:?} to AVM2: {}", event, e);
}
}
_ => {}
};
}
/// Executes and propagates the given clip event. /// Executes and propagates the given clip event.
/// Events execute inside-out; the deepest child will react first, followed /// Events execute inside-out; the deepest child will react first, followed
/// by its parent, and so forth. /// by its parent, and so forth.

View File

@ -2179,6 +2179,8 @@ impl<'gc> TInteractiveObject<'gc> for MovieClip<'gc> {
} }
} }
} }
} else {
self.event_dispatch_to_avm2(context, event);
} }
handled handled

View File

@ -720,6 +720,8 @@ impl<'gc> TInteractiveObject<'gc> for Stage<'gc> {
_context: &mut UpdateContext<'_, 'gc, '_>, _context: &mut UpdateContext<'_, 'gc, '_>,
_event: ClipEvent, _event: ClipEvent,
) -> ClipEventResult { ) -> ClipEventResult {
//NOTE: Stage does not appear to fire common InteractiveObject events
//within AVM2.
ClipEventResult::Handled ClipEventResult::Handled
} }
} }