core: Correct the order of events that are fired when an `Avm2Button` is instantiated on the timeline.
This commit is contained in:
parent
6a70c1b3e0
commit
11d7fe5107
|
@ -71,7 +71,7 @@ pub fn set_down_state<'gc>(
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|val| val.as_display_object());
|
.and_then(|val| val.as_display_object());
|
||||||
|
|
||||||
btn.set_state_child(activation.context.gc_context, ButtonState::DOWN, new_state);
|
btn.set_state_child(&mut activation.context, ButtonState::DOWN, new_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
|
@ -114,7 +114,7 @@ pub fn set_over_state<'gc>(
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|val| val.as_display_object());
|
.and_then(|val| val.as_display_object());
|
||||||
|
|
||||||
btn.set_state_child(activation.context.gc_context, ButtonState::OVER, new_state);
|
btn.set_state_child(&mut activation.context, ButtonState::OVER, new_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
|
@ -157,11 +157,7 @@ pub fn set_hit_test_state<'gc>(
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|val| val.as_display_object());
|
.and_then(|val| val.as_display_object());
|
||||||
|
|
||||||
btn.set_state_child(
|
btn.set_state_child(&mut activation.context, ButtonState::HIT_TEST, new_state);
|
||||||
activation.context.gc_context,
|
|
||||||
ButtonState::HIT_TEST,
|
|
||||||
new_state,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
|
@ -204,7 +200,7 @@ pub fn set_up_state<'gc>(
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|val| val.as_display_object());
|
.and_then(|val| val.as_display_object());
|
||||||
|
|
||||||
btn.set_state_child(activation.context.gc_context, ButtonState::UP, new_state);
|
btn.set_state_child(&mut activation.context, ButtonState::UP, new_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Undefined)
|
Ok(Value::Undefined)
|
||||||
|
|
|
@ -157,11 +157,14 @@ impl<'gc> Avm2Button<'gc> {
|
||||||
/// button children. This means that, for example, a child that exists in
|
/// button children. This means that, for example, a child that exists in
|
||||||
/// multiple states in the SWF will actually be instantiated multiple
|
/// multiple states in the SWF will actually be instantiated multiple
|
||||||
/// times.
|
/// times.
|
||||||
|
///
|
||||||
|
/// If the boolean parameter is `true`, then the caller of this function
|
||||||
|
/// should signal events on all children of the returned display object.
|
||||||
fn create_state(
|
fn create_state(
|
||||||
self,
|
self,
|
||||||
context: &mut UpdateContext<'_, 'gc, '_>,
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
swf_state: swf::ButtonState,
|
swf_state: swf::ButtonState,
|
||||||
) -> DisplayObject<'gc> {
|
) -> (DisplayObject<'gc>, bool) {
|
||||||
let movie = self
|
let movie = self
|
||||||
.movie()
|
.movie()
|
||||||
.expect("All SWF-defined buttons should have movies");
|
.expect("All SWF-defined buttons should have movies");
|
||||||
|
@ -234,22 +237,17 @@ impl<'gc> Avm2Button<'gc> {
|
||||||
child.post_instantiation(context, child, None, Instantiator::Movie, false);
|
child.post_instantiation(context, child, None, Instantiator::Movie, false);
|
||||||
child.construct_frame(context);
|
child.construct_frame(context);
|
||||||
|
|
||||||
child
|
(child, false)
|
||||||
} else {
|
} else {
|
||||||
for (child, depth) in children {
|
for (child, depth) in children {
|
||||||
let removed_child = state_sprite.replace_at_depth(context, child, depth.into());
|
state_sprite.replace_at_depth(context, child, depth.into());
|
||||||
|
|
||||||
child.set_parent(context.gc_context, Some(self.into()));
|
child.set_parent(context.gc_context, Some(self.into()));
|
||||||
child.post_instantiation(context, child, None, Instantiator::Movie, false);
|
child.post_instantiation(context, child, None, Instantiator::Movie, false);
|
||||||
child.construct_frame(context);
|
child.construct_frame(context);
|
||||||
|
|
||||||
dispatch_added_event(self.into(), child, false, context);
|
|
||||||
if let Some(removed_child) = removed_child {
|
|
||||||
dispatch_removed_event(removed_child, context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state_sprite.into()
|
(state_sprite.into(), true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,17 +270,28 @@ impl<'gc> Avm2Button<'gc> {
|
||||||
/// Set the display object that represents a particular button state.
|
/// Set the display object that represents a particular button state.
|
||||||
pub fn set_state_child(
|
pub fn set_state_child(
|
||||||
self,
|
self,
|
||||||
gc_context: MutationContext<'gc, '_>,
|
context: &mut UpdateContext<'_, 'gc, '_>,
|
||||||
state: swf::ButtonState,
|
state: swf::ButtonState,
|
||||||
child: Option<DisplayObject<'gc>>,
|
child: Option<DisplayObject<'gc>>,
|
||||||
) {
|
) {
|
||||||
|
let child_was_on_stage = child.map(|c| c.is_on_stage(context)).unwrap_or(false);
|
||||||
|
let old_state_child = self.get_state_child(state);
|
||||||
|
|
||||||
match state {
|
match state {
|
||||||
swf::ButtonState::UP => self.0.write(gc_context).up_state = child,
|
swf::ButtonState::UP => self.0.write(context.gc_context).up_state = child,
|
||||||
swf::ButtonState::OVER => self.0.write(gc_context).over_state = child,
|
swf::ButtonState::OVER => self.0.write(context.gc_context).over_state = child,
|
||||||
swf::ButtonState::DOWN => self.0.write(gc_context).down_state = child,
|
swf::ButtonState::DOWN => self.0.write(context.gc_context).down_state = child,
|
||||||
swf::ButtonState::HIT_TEST => self.0.write(gc_context).hit_area = child,
|
swf::ButtonState::HIT_TEST => self.0.write(context.gc_context).hit_area = child,
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(new_state_child) = child {
|
||||||
|
dispatch_added_event(self.into(), new_state_child, child_was_on_stage, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(old_state_child) = old_state_child {
|
||||||
|
dispatch_removed_event(old_state_child, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enabled(self) -> bool {
|
pub fn enabled(self) -> bool {
|
||||||
|
@ -366,10 +375,11 @@ impl<'gc> TDisplayObject<'gc> for Avm2Button<'gc> {
|
||||||
);
|
);
|
||||||
self.0.write(context.gc_context).object = Some(object.into());
|
self.0.write(context.gc_context).object = Some(object.into());
|
||||||
|
|
||||||
let up_state = self.create_state(context, swf::ButtonState::UP);
|
let (up_state, up_should_fire) = self.create_state(context, swf::ButtonState::UP);
|
||||||
let over_state = self.create_state(context, swf::ButtonState::OVER);
|
let (over_state, over_should_fire) = self.create_state(context, swf::ButtonState::OVER);
|
||||||
let down_state = self.create_state(context, swf::ButtonState::DOWN);
|
let (down_state, down_should_fire) = self.create_state(context, swf::ButtonState::DOWN);
|
||||||
let hit_area = self.create_state(context, swf::ButtonState::HIT_TEST);
|
let (hit_area, hit_should_fire) =
|
||||||
|
self.create_state(context, swf::ButtonState::HIT_TEST);
|
||||||
|
|
||||||
let mut write = self.0.write(context.gc_context);
|
let mut write = self.0.write(context.gc_context);
|
||||||
write.up_state = Some(up_state);
|
write.up_state = Some(up_state);
|
||||||
|
@ -380,6 +390,42 @@ impl<'gc> TDisplayObject<'gc> for Avm2Button<'gc> {
|
||||||
|
|
||||||
drop(write);
|
drop(write);
|
||||||
|
|
||||||
|
if up_should_fire {
|
||||||
|
if let Some(up_container) = up_state.as_container() {
|
||||||
|
for (_depth, child) in up_container.iter_depth_list() {
|
||||||
|
dispatch_added_event((*self).into(), child, false, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if over_should_fire {
|
||||||
|
if let Some(over_container) = over_state.as_container() {
|
||||||
|
for (_depth, child) in over_container.iter_depth_list() {
|
||||||
|
dispatch_added_event((*self).into(), child, false, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if down_should_fire {
|
||||||
|
if let Some(down_container) = down_state.as_container() {
|
||||||
|
for (_depth, child) in down_container.iter_depth_list() {
|
||||||
|
dispatch_added_event((*self).into(), child, false, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if hit_should_fire {
|
||||||
|
if let Some(hit_container) = hit_area.as_container() {
|
||||||
|
for (_depth, child) in hit_container.iter_depth_list() {
|
||||||
|
dispatch_added_event((*self).into(), child, false, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.frame_constructed(context);
|
||||||
|
|
||||||
|
//NOTE: Yes, we do have to run these in a different order from the
|
||||||
|
//regular run_frame method.
|
||||||
up_state.run_frame(context);
|
up_state.run_frame(context);
|
||||||
over_state.run_frame(context);
|
over_state.run_frame(context);
|
||||||
down_state.run_frame(context);
|
down_state.run_frame(context);
|
||||||
|
@ -389,6 +435,8 @@ impl<'gc> TDisplayObject<'gc> for Avm2Button<'gc> {
|
||||||
over_state.run_frame_scripts(context);
|
over_state.run_frame_scripts(context);
|
||||||
down_state.run_frame_scripts(context);
|
down_state.run_frame_scripts(context);
|
||||||
hit_area.run_frame_scripts(context);
|
hit_area.run_frame_scripts(context);
|
||||||
|
|
||||||
|
self.exit_frame(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue