Skip to content

Commit

Permalink
avm1: Allow button.enabled to hold any value
Browse files Browse the repository at this point in the history
  • Loading branch information
Toad06 authored and relrelb committed Apr 30, 2023
1 parent 86c2707 commit ee74039
Show file tree
Hide file tree
Showing 16 changed files with 122 additions and 98 deletions.
28 changes: 3 additions & 25 deletions core/src/avm1/globals/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ macro_rules! button_setter {
}

const PROTO_DECLS: &[Declaration] = declare_properties! {
"enabled" => property(button_getter!(enabled), button_setter!(set_enabled));
"getDepth" => method(globals::get_depth; DONT_ENUM | DONT_DELETE | READ_ONLY | VERSION_6);
"enabled" => bool(true);
"getDepth" => method(globals::get_depth; DONT_DELETE | READ_ONLY | VERSION_6);
"useHandCursor" => property(button_getter!(use_hand_cursor), button_setter!(set_use_hand_cursor));
"blendMode" => property(button_getter!(blend_mode), button_setter!(set_blend_mode); DONT_DELETE | DONT_ENUM);
"blendMode" => property(button_getter!(blend_mode), button_setter!(set_blend_mode); DONT_DELETE);
};

pub fn create_proto<'gc>(
Expand All @@ -63,28 +63,6 @@ pub fn constructor<'gc>(
Ok(this.into())
}

fn enabled<'gc>(
this: Avm1Button<'gc>,
_activation: &mut Activation<'_, 'gc>,
) -> Result<Value<'gc>, Error<'gc>> {
// TODO: This property should return the value set by the user.
Ok(this.enabled().into())
}

fn set_enabled<'gc>(
this: Avm1Button<'gc>,
activation: &mut Activation<'_, 'gc>,
value: Value<'gc>,
) -> Result<(), Error<'gc>> {
let enabled = if matches!(value, Value::Undefined) {
true
} else {
value.as_bool(activation.swf_version())
};
this.set_enabled(&mut activation.context, enabled);
Ok(())
}

fn use_hand_cursor<'gc>(
this: Avm1Button<'gc>,
_activation: &mut Activation<'_, 'gc>,
Expand Down
24 changes: 1 addition & 23 deletions core/src/avm1/globals/movie_clip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const PROTO_DECLS: &[Declaration] = declare_properties! {
"attachBitmap" => method(mc_method!(attach_bitmap); DONT_ENUM | DONT_DELETE | VERSION_8);
"removeMovieClip" => method(remove_movie_clip; DONT_ENUM | DONT_DELETE);
"transform" => property(mc_getter!(transform), mc_setter!(set_transform); DONT_ENUM | VERSION_8);
"enabled" => property(mc_getter!(enabled), mc_setter!(set_enabled); DONT_DELETE | DONT_ENUM);
"enabled" => bool(true; DONT_ENUM);
"_lockroot" => property(mc_getter!(lock_root), mc_setter!(set_lock_root); DONT_DELETE | DONT_ENUM);
"useHandCursor" => property(mc_getter!(use_hand_cursor), mc_setter!(set_use_hand_cursor); DONT_DELETE | DONT_ENUM);
"blendMode" => property(mc_getter!(blend_mode), mc_setter!(set_blend_mode); DONT_DELETE | DONT_ENUM);
Expand Down Expand Up @@ -1409,28 +1409,6 @@ fn set_transform<'gc>(
Ok(())
}

fn enabled<'gc>(
this: MovieClip<'gc>,
_activation: &mut Activation<'_, 'gc>,
) -> Result<Value<'gc>, Error<'gc>> {
// TODO: This property should return the value set by the user.
Ok(this.enabled().into())
}

fn set_enabled<'gc>(
this: MovieClip<'gc>,
activation: &mut Activation<'_, 'gc>,
value: Value<'gc>,
) -> Result<(), Error<'gc>> {
let enabled = if matches!(value, Value::Undefined) {
true
} else {
value.as_bool(activation.swf_version())
};
this.set_enabled(&mut activation.context, enabled);
Ok(())
}

fn lock_root<'gc>(
this: MovieClip<'gc>,
_activation: &mut Activation<'_, 'gc>,
Expand Down
4 changes: 2 additions & 2 deletions core/src/avm2/globals/flash/display/movie_clip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ pub fn get_enabled<'gc>(
.and_then(|o| o.as_display_object())
.and_then(|dobj| dobj.as_movie_clip())
{
return Ok(mc.enabled().into());
return Ok(mc.avm2_enabled().into());
}

Ok(Value::Undefined)
Expand All @@ -221,7 +221,7 @@ pub fn set_enabled<'gc>(
{
let enabled = args.get_bool(0);

mc.set_enabled(&mut activation.context, enabled);
mc.set_avm2_enabled(&mut activation.context, enabled);
}

Ok(Value::Undefined)
Expand Down
41 changes: 28 additions & 13 deletions core/src/display_object/avm1_button.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::avm1::{Object, StageObject, Value};
use crate::avm1::{Activation, ActivationIdentifier, Object, StageObject, TObject, Value};
use crate::backend::ui::MouseCursor;
use crate::context::{ActionType, RenderContext, UpdateContext};
use crate::display_object::container::{
Expand Down Expand Up @@ -43,7 +43,6 @@ pub struct Avm1ButtonData<'gc> {
object: Option<Object<'gc>>,
initialized: bool,
has_focus: bool,
enabled: bool,
use_hand_cursor: bool,
}

Expand Down Expand Up @@ -90,7 +89,6 @@ impl<'gc> Avm1Button<'gc> {
ButtonTracking::Push
},
has_focus: false,
enabled: true,
use_hand_cursor: true,
},
))
Expand Down Expand Up @@ -197,12 +195,23 @@ impl<'gc> Avm1Button<'gc> {
}
}

pub fn enabled(self) -> bool {
self.0.read().enabled
}

pub fn set_enabled(self, context: &mut UpdateContext<'_, 'gc>, enabled: bool) {
self.0.write(context.gc_context).enabled = enabled;
pub fn enabled(self, context: &mut UpdateContext<'_, 'gc>) -> bool {
if let Some(object) = self.0.read().object {
let mut activation = Activation::from_stub(
context.reborrow(),
ActivationIdentifier::root("[AVM1 Button Enabled]"),
);
if let Ok(enabled) = object.get("enabled", &mut activation) {
match enabled {
Value::Undefined => true,
_ => enabled.as_bool(activation.swf_version()),
}
} else {
true
}
} else {
false
}
}

pub fn use_hand_cursor(self) -> bool {
Expand Down Expand Up @@ -421,7 +430,11 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> {
self.into()
}

fn filter_clip_event(self, _event: ClipEvent) -> ClipEventResult {
fn filter_clip_event(
self,
_context: &mut UpdateContext<'_, 'gc>,
_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".
Expand All @@ -438,6 +451,8 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> {
event: ClipEvent,
) -> ClipEventResult {
let self_display_object = self.into();
let is_enabled = self.enabled(context);

let mut write = self.0.write(context.gc_context);

// Translate the clip event to a button event, based on how the button state changes.
Expand Down Expand Up @@ -489,7 +504,7 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> {
_ => return ClipEventResult::NotHandled,
};

let (update_state, new_state) = if write.enabled {
let (update_state, new_state) = if is_enabled {
write.run_actions(context, condition, None);
write.play_sound(context, sound);

Expand Down Expand Up @@ -557,8 +572,8 @@ impl<'gc> TInteractiveObject<'gc> for Avm1Button<'gc> {
None
}

fn mouse_cursor(self, _context: &mut UpdateContext<'_, 'gc>) -> MouseCursor {
if self.use_hand_cursor() && self.enabled() {
fn mouse_cursor(self, context: &mut UpdateContext<'_, 'gc>) -> MouseCursor {
if self.use_hand_cursor() && self.enabled(context) {
MouseCursor::Hand
} else {
MouseCursor::Arrow
Expand Down
6 changes: 5 additions & 1 deletion core/src/display_object/avm2_button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,11 @@ impl<'gc> TInteractiveObject<'gc> for Avm2Button<'gc> {
self.into()
}

fn filter_clip_event(self, event: ClipEvent) -> ClipEventResult {
fn filter_clip_event(
self,
_context: &mut UpdateContext<'_, 'gc>,
event: ClipEvent,
) -> ClipEventResult {
if !self.visible() {
return ClipEventResult::NotHandled;
}
Expand Down
6 changes: 5 additions & 1 deletion core/src/display_object/edit_text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1797,7 +1797,11 @@ impl<'gc> TInteractiveObject<'gc> for EditText<'gc> {
self.into()
}

fn filter_clip_event(self, event: ClipEvent) -> ClipEventResult {
fn filter_clip_event(
self,
_context: &mut UpdateContext<'_, 'gc>,
event: ClipEvent,
) -> ClipEventResult {
if event != ClipEvent::Press {
return ClipEventResult::NotHandled;
}
Expand Down
8 changes: 6 additions & 2 deletions core/src/display_object/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,11 @@ pub trait TInteractiveObject<'gc>:
/// machinery should run. Otherwise, the event will not be handled, neither
/// by this interactive object nor it's children. The event will be passed
/// onto other siblings of the display object instead.
fn filter_clip_event(self, event: ClipEvent) -> ClipEventResult;
fn filter_clip_event(
self,
_context: &mut UpdateContext<'_, 'gc>,
event: ClipEvent,
) -> ClipEventResult;

/// Propagate the event to children.
///
Expand Down Expand Up @@ -424,7 +428,7 @@ pub trait TInteractiveObject<'gc>:
return ClipEventResult::NotHandled;
}

if self.filter_clip_event(event) == ClipEventResult::NotHandled {
if self.filter_clip_event(context, event) == ClipEventResult::NotHandled {
return ClipEventResult::NotHandled;
}

Expand Down
6 changes: 5 additions & 1 deletion core/src/display_object/loader_display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,11 @@ impl<'gc> TInteractiveObject<'gc> for LoaderDisplay<'gc> {
self.into()
}

fn filter_clip_event(self, _event: ClipEvent) -> ClipEventResult {
fn filter_clip_event(
self,
_context: &mut UpdateContext<'_, 'gc>,
_event: ClipEvent,
) -> ClipEventResult {
ClipEventResult::NotHandled
}
fn event_dispatch(
Expand Down
70 changes: 50 additions & 20 deletions core/src/display_object/movie_clip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ pub struct MovieClipData<'gc> {
avm2_class: Option<Avm2ClassObject<'gc>>,
drawing: Drawing,
has_focus: bool,
enabled: bool,
avm2_enabled: bool,

/// Show a hand cursor when the clip is in button mode.
use_hand_cursor: bool,
Expand Down Expand Up @@ -154,7 +154,7 @@ impl<'gc> MovieClip<'gc> {
avm2_class: None,
drawing: Drawing::new(),
has_focus: false,
enabled: true,
avm2_enabled: true,
use_hand_cursor: true,
button_mode: false,
last_queued_script_frame: None,
Expand Down Expand Up @@ -193,7 +193,7 @@ impl<'gc> MovieClip<'gc> {
avm2_class: Some(class),
drawing: Drawing::new(),
has_focus: false,
enabled: true,
avm2_enabled: true,
use_hand_cursor: true,
button_mode: false,
last_queued_script_frame: None,
Expand Down Expand Up @@ -236,7 +236,7 @@ impl<'gc> MovieClip<'gc> {
avm2_class: None,
drawing: Drawing::new(),
has_focus: false,
enabled: true,
avm2_enabled: true,
use_hand_cursor: true,
button_mode: false,
last_queued_script_frame: None,
Expand Down Expand Up @@ -301,7 +301,7 @@ impl<'gc> MovieClip<'gc> {
avm2_class: None,
drawing: Drawing::new(),
has_focus: false,
enabled: true,
avm2_enabled: true,
use_hand_cursor: true,
button_mode: false,
last_queued_script_frame: None,
Expand Down Expand Up @@ -2208,12 +2208,40 @@ impl<'gc> MovieClip<'gc> {
Ok(())
}

pub fn enabled(self) -> bool {
self.0.read().enabled
fn enabled(self, context: &mut UpdateContext<'_, 'gc>) -> bool {
if !context.is_action_script_3() {
self.avm1_enabled(context)
} else {
self.avm2_enabled()
}
}

pub fn set_enabled(self, context: &mut UpdateContext<'_, 'gc>, enabled: bool) {
self.0.write(context.gc_context).enabled = enabled;
fn avm1_enabled(self, context: &mut UpdateContext<'_, 'gc>) -> bool {
let object = self.object();
if let Avm1Value::Object(object) = object {
let mut activation = Avm1Activation::from_stub(
context.reborrow(),
ActivationIdentifier::root("[AVM1 MovieClip Enabled]"),
);
if let Ok(enabled) = object.get("enabled", &mut activation) {
match enabled {
Avm1Value::Undefined => true,
_ => enabled.as_bool(activation.swf_version()),
}
} else {
true
}
} else {
false
}
}

pub fn avm2_enabled(self) -> bool {
self.0.read().avm2_enabled
}

pub fn set_avm2_enabled(self, context: &mut UpdateContext<'_, 'gc>, enabled: bool) {
self.0.write(context.gc_context).avm2_enabled = enabled;
}

pub fn use_hand_cursor(self) -> bool {
Expand Down Expand Up @@ -2783,17 +2811,19 @@ impl<'gc> TInteractiveObject<'gc> for MovieClip<'gc> {
self.into()
}

fn filter_clip_event(self, event: ClipEvent) -> ClipEventResult {
if event.is_button_event() && !self.visible() && !matches!(event, ClipEvent::ReleaseOutside)
{
return ClipEventResult::NotHandled;
}
fn filter_clip_event(
self,
context: &mut UpdateContext<'_, 'gc>,
event: ClipEvent,
) -> ClipEventResult {
if event.is_button_event() {
if !self.visible() && !matches!(event, ClipEvent::ReleaseOutside) {
return ClipEventResult::NotHandled;
}

if !self.enabled()
&& event.is_button_event()
&& !matches!(event, ClipEvent::KeyPress { .. })
{
return ClipEventResult::NotHandled;
if !self.enabled(context) && !matches!(event, ClipEvent::KeyPress { .. }) {
return ClipEventResult::NotHandled;
}
}

ClipEventResult::Handled
Expand Down Expand Up @@ -3090,7 +3120,7 @@ impl<'gc> TInteractiveObject<'gc> for MovieClip<'gc> {
}

fn mouse_cursor(self, context: &mut UpdateContext<'_, 'gc>) -> MouseCursor {
if self.use_hand_cursor() && self.enabled() && self.is_button_mode(context) {
if self.use_hand_cursor() && self.enabled(context) && self.is_button_mode(context) {
MouseCursor::Hand
} else {
MouseCursor::Arrow
Expand Down
6 changes: 5 additions & 1 deletion core/src/display_object/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -867,7 +867,11 @@ impl<'gc> TInteractiveObject<'gc> for Stage<'gc> {
self.into()
}

fn filter_clip_event(self, _event: ClipEvent) -> ClipEventResult {
fn filter_clip_event(
self,
_context: &mut UpdateContext<'_, 'gc>,
_event: ClipEvent,
) -> ClipEventResult {
ClipEventResult::Handled
}

Expand Down
Binary file not shown.
Loading

0 comments on commit ee74039

Please sign in to comment.