avm1: Fix some issues with buttons

This commit is contained in:
Toad06 2023-04-24 15:19:57 +02:00 committed by Nathan Adams
parent 4432c45eb3
commit ad4dc943fa
7 changed files with 251 additions and 29 deletions

View File

@ -203,9 +203,6 @@ impl<'gc> Avm1Button<'gc> {
pub fn set_enabled(self, context: &mut UpdateContext<'_, 'gc>, enabled: bool) {
self.0.write(context.gc_context).enabled = enabled;
if !enabled {
self.set_state(context, ButtonState::Up);
}
}
pub fn use_hand_cursor(self) -> bool {
@ -424,16 +421,15 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> {
self.into()
}
fn filter_clip_event(self, event: ClipEvent) -> ClipEventResult {
if !self.visible() && !matches!(event, ClipEvent::ReleaseOutside) {
return ClipEventResult::NotHandled;
fn filter_clip_event(self, _event: ClipEvent) -> ClipEventResult {
// An invisible button can still run its `rollOut` or `releaseOutside` event.
// A disabled button doesn't run its events (`KeyPress` being the exception) but
// its state can still change. This is tested at "avm1/mouse_events_visible_enabled".
if !self.visible() && self.0.read().state == ButtonState::Up {
ClipEventResult::NotHandled
} else {
ClipEventResult::Handled
}
if !self.enabled() && !matches!(event, ClipEvent::KeyPress { .. }) {
return ClipEventResult::NotHandled;
}
ClipEventResult::Handled
}
fn event_dispatch(
@ -493,26 +489,41 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> {
_ => return ClipEventResult::NotHandled,
};
write.run_actions(context, condition, None);
write.play_sound(context, sound);
let (update_state, new_state) = if write.enabled {
write.run_actions(context, condition, None);
write.play_sound(context, sound);
// Queue ActionScript-defined event handlers after the SWF defined ones.
// (e.g., clip.onRelease = foo).
if context.swf.version() >= 6 {
if let Some(name) = event.method_name() {
context.action_queue.queue_action(
self_display_object,
ActionType::Method {
object: write.object.unwrap(),
name,
args: vec![],
},
false,
);
// Queue ActionScript-defined event handlers after the SWF defined ones.
// (e.g., clip.onRelease = foo).
if context.swf.version() >= 6 {
if let Some(name) = event.method_name() {
context.action_queue.queue_action(
self_display_object,
ActionType::Method {
object: write.object.unwrap(),
name,
args: vec![],
},
false,
);
}
}
}
if write.state != new_state {
(write.state != new_state, new_state)
} else {
// Remove the current mouse hovered and mouse down objects.
// This is required to make sure the button will fire its events if it gets enabled.
if InteractiveObject::option_ptr_eq(self.as_interactive(), context.mouse_over_object) {
context.mouse_over_object = None;
}
if InteractiveObject::option_ptr_eq(self.as_interactive(), context.mouse_down_object) {
context.mouse_down_object = None;
}
(new_state != ButtonState::Over, ButtonState::Up)
};
if update_state {
drop(write);
self.set_state(context, new_state);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@ -0,0 +1,113 @@
[
{
"type": "MouseMove",
"pos": [100.0, 100.0]
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "MouseDown",
"pos": [110.0, 110.0],
"btn": "Left"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "MouseUp",
"pos": [120.0, 120.0],
"btn": "Left"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "MouseDown",
"pos": [130.0, 130.0],
"btn": "Left"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "MouseUp",
"pos": [140.0, 140.0],
"btn": "Left"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "MouseMove",
"pos": [2.0, 2.0]
},
{
"type": "MouseMove",
"pos": [150.0, 150.0]
},
{
"type": "MouseDown",
"pos": [150.0, 150.0],
"btn": "Middle"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "Wait"
},
{
"type": "MouseUp",
"pos": [160.0, 160.0],
"btn": "Middle"
},
{
"type": "Wait"
},
{
"type": "Wait"
}
]

View File

@ -0,0 +1,12 @@
Step 1: rollOver
Step 2: rollOut
Step 3: rollOver
Step 4: from onEnterFrame
Step 5: from onEnterFrame
Step 6: press
Step 7: releaseOutside
Step 8: rollOver
Step 9: press
Step 10: from onEnterFrame
Step 11: from onEnterFrame
Step 12: rollOver

View File

@ -0,0 +1,78 @@
// Source code for the `rollOver` event.
// Other events just do `buttonAction("event_name");`.
if(_root.step === undefined) {
_root.step = 1;
_root.nextStep = -1;
_root.onEnterFrame = function() {
if(step === 11 && Key.isDown(4)) {
_root.doin.enabled = true;
nextStep = 0;
}
if(nextStep < 0) {
return;
}
nextStep--;
if(nextStep < 0) {
buttonAction("from onEnterFrame");
}
};
_root.buttonAction = function(event) {
var button = _root.doin;
switch(step) {
case 1:
// The mouse moved inside of the button area, this triggers the rollOver event.
button._visible = false;
break;
case 2:
// The visibility was set to off, this triggers the rollOut event.
button._visible = true;
break;
case 3:
// The visibility was restored, this triggers the rollOver event again.
button.enabled = false;
nextStep = 1;
break;
case 4:
// The button was disabled, this didn't trigger the rollOut event.
button.enabled = true;
nextStep = 1;
break;
case 5:
// The button was enabled again, this didn't trigger the rollOver event.
break;
case 6:
// The mouse left button was pressed, this triggers the press event.
button._visible = false;
break;
case 7:
// The visibility of the AS button was set to off, then the mouse left button was released. This triggers the releaseOutside event.
button._visible = true;
break;
case 8:
// The visibility was restored, this triggers the rollOver event again.
break;
case 9:
// The mouse left button was pressed, this triggers the press event.
button.enabled = false;
nextStep = 1;
break;
case 10:
// The AS button was disabled, then the mouse left button was released. This didn't trigger the release or releaseOutside event.
break;
case 11:
// The mouse moved outside of the button area, got back inside and the mouse middle button was pressed. No event did trigger.
button.enabled = true;
break;
case 12:
// The button was enabled again, this triggers the rollOver event.
// The button is then disabled one more time, for image comparison.
button.enabled = false;
break;
}
trace("Step " + step + ": " + event);
step++;
};
}
buttonAction("rollOver");

View File

@ -0,0 +1,8 @@
num_frames = 40
[image_comparison]
tolerance = 0
[player_options]
with_renderer = { optional = true, sample_count = 1 }