core: `Stage`, `EditText`, and `Avm2Button` should also be interactive objects.

This commit is contained in:
David Wendt 2021-10-02 20:20:43 -04:00 committed by kmeisthax
parent e71c749db5
commit 95f105aadd
16 changed files with 249 additions and 1 deletions

View File

@ -7,6 +7,9 @@ use crate::backend::ui::MouseCursor;
use crate::context::{RenderContext, UpdateContext};
use crate::display_object::avm1_button::{ButtonState, ButtonTracking};
use crate::display_object::container::{dispatch_added_event, dispatch_removed_event};
use crate::display_object::interactive::{
InteractiveObject, InteractiveObjectBase, TInteractiveObject,
};
use crate::display_object::{DisplayObjectBase, MovieClip, TDisplayObject};
use crate::events::{ClipEvent, ClipEventResult};
use crate::prelude::*;
@ -14,6 +17,7 @@ use crate::tag_utils::{SwfMovie, SwfSlice};
use crate::types::{Degrees, Percent};
use crate::vminterface::Instantiator;
use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
use std::sync::Arc;
#[derive(Clone, Debug, Collect, Copy)]
@ -24,6 +28,8 @@ pub struct Avm2Button<'gc>(GcCell<'gc, Avm2ButtonData<'gc>>);
#[collect(no_drop)]
pub struct Avm2ButtonData<'gc> {
base: DisplayObjectBase<'gc>,
interactive_base: InteractiveObjectBase,
static_data: GcCell<'gc, ButtonStatic>,
/// The current button state to render.
@ -96,6 +102,7 @@ impl<'gc> Avm2Button<'gc> {
context.gc_context,
Avm2ButtonData {
base: Default::default(),
interactive_base: Default::default(),
static_data: GcCell::allocate(context.gc_context, static_data),
state: self::ButtonState::Up,
hit_area: None,
@ -689,6 +696,10 @@ impl<'gc> TDisplayObject<'gc> for Avm2Button<'gc> {
Some(*self)
}
fn as_interactive(self) -> Option<InteractiveObject<'gc>> {
Some(self.into())
}
fn allow_as_mask(&self) -> bool {
let state = self.0.read().state;
let current_state = self.get_state_child(state.into());
@ -777,6 +788,16 @@ impl<'gc> TDisplayObject<'gc> for Avm2Button<'gc> {
}
}
impl<'gc> TInteractiveObject<'gc> for Avm2Button<'gc> {
fn base(&self) -> Ref<InteractiveObjectBase> {
Ref::map(self.0.read(), |r| &r.interactive_base)
}
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<InteractiveObjectBase> {
RefMut::map(self.0.write(mc), |w| &mut w.interactive_base)
}
}
impl<'gc> Avm2ButtonData<'gc> {
fn play_sound(
&self,

View File

@ -10,6 +10,9 @@ use crate::avm2::{
};
use crate::backend::ui::MouseCursor;
use crate::context::{RenderContext, UpdateContext};
use crate::display_object::interactive::{
InteractiveObject, InteractiveObjectBase, TInteractiveObject,
};
use crate::display_object::{DisplayObjectBase, TDisplayObject};
use crate::drawing::Drawing;
use crate::events::{ButtonKeyCode, ClipEvent, ClipEventResult, KeyCode};
@ -25,7 +28,7 @@ use crate::vminterface::{AvmObject, AvmType, Instantiator};
use crate::xml::XmlDocument;
use chrono::Utc;
use gc_arena::{Collect, Gc, GcCell, MutationContext};
use std::{cell::Ref, sync::Arc};
use std::{cell::Ref, cell::RefMut, sync::Arc};
use swf::Twips;
/// Boxed error type.
@ -60,6 +63,9 @@ pub struct EditTextData<'gc> {
/// DisplayObject common properties.
base: DisplayObjectBase<'gc>,
/// InteractiveObject common properties.
interactive_base: InteractiveObjectBase,
/// Static data shared among all instances of this `EditText`.
static_data: Gc<'gc, EditTextStatic>,
@ -283,6 +289,7 @@ impl<'gc> EditText<'gc> {
context.gc_context,
EditTextData {
base,
interactive_base: Default::default(),
document,
text_spans,
static_data: gc_arena::Gc::allocate(
@ -1557,6 +1564,10 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
Some(*self)
}
fn as_interactive(self) -> Option<InteractiveObject<'gc>> {
Some(self.into())
}
fn post_instantiation(
&self,
context: &mut UpdateContext<'_, 'gc, '_>,
@ -1881,6 +1892,16 @@ impl<'gc> TDisplayObject<'gc> for EditText<'gc> {
}
}
impl<'gc> TInteractiveObject<'gc> for EditText<'gc> {
fn base(&self) -> Ref<InteractiveObjectBase> {
Ref::map(self.0.read(), |r| &r.interactive_base)
}
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<InteractiveObjectBase> {
RefMut::map(self.0.write(mc), |w| &mut w.interactive_base)
}
}
/// Static data shared between all instances of a text object.
#[derive(Debug, Clone, Collect)]
#[collect(no_drop)]

View File

@ -1,6 +1,9 @@
//! Interactive object enumtrait
use crate::display_object::avm2_button::Avm2Button;
use crate::display_object::edit_text::EditText;
use crate::display_object::movie_clip::MovieClip;
use crate::display_object::stage::Stage;
use bitflags::bitflags;
use gc_arena::{Collect, MutationContext};
use ruffle_macros::enum_trait_object;
@ -39,7 +42,10 @@ impl Default for InteractiveObjectBase {
#[derive(Clone, Collect, Debug, Copy)]
#[collect(no_drop)]
pub enum InteractiveObject<'gc> {
Stage(Stage<'gc>),
Avm2Button(Avm2Button<'gc>),
MovieClip(MovieClip<'gc>),
EditText(EditText<'gc>),
}
)]
pub trait TInteractiveObject<'gc>:

View File

@ -11,12 +11,16 @@ use crate::context::{RenderContext, UpdateContext};
use crate::display_object::container::{
ChildContainer, DisplayObjectContainer, TDisplayObjectContainer,
};
use crate::display_object::interactive::{
InteractiveObject, InteractiveObjectBase, TInteractiveObject,
};
use crate::display_object::{render_base, DisplayObject, DisplayObjectBase, TDisplayObject};
use crate::prelude::*;
use crate::types::{Degrees, Percent};
use crate::vminterface::{AvmType, Instantiator};
use bitflags::bitflags;
use gc_arena::{Collect, GcCell, MutationContext};
use std::cell::{Ref, RefMut};
use std::fmt::{self, Display, Formatter};
use std::str::FromStr;
@ -36,6 +40,9 @@ pub struct StageData<'gc> {
/// parent, as the stage does not respect it.
base: DisplayObjectBase<'gc>,
/// Base properties for interactive display objects.
interactive_base: InteractiveObjectBase,
/// The list of all children of the stage.
///
/// Stage children are exposed to AVM1 as `_level*n*` on all stage objects.
@ -98,6 +105,7 @@ impl<'gc> Stage<'gc> {
gc_context,
StageData {
base: Default::default(),
interactive_base: Default::default(),
child: Default::default(),
background_color: None,
letterbox: Letterbox::Fullscreen,
@ -549,6 +557,10 @@ impl<'gc> TDisplayObject<'gc> for Stage<'gc> {
Some(self.into())
}
fn as_interactive(self) -> Option<InteractiveObject<'gc>> {
Some(self.into())
}
fn as_stage(&self) -> Option<Stage<'gc>> {
Some(*self)
}
@ -588,6 +600,16 @@ impl<'gc> TDisplayObjectContainer<'gc> for Stage<'gc> {
impl_display_object_container!(child);
}
impl<'gc> TInteractiveObject<'gc> for Stage<'gc> {
fn base(&self) -> Ref<InteractiveObjectBase> {
Ref::map(self.0.read(), |r| &r.interactive_base)
}
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<InteractiveObjectBase> {
RefMut::map(self.0.write(mc), |w| &mut w.interactive_base)
}
}
pub struct ParseEnumError;
/// The scale mode of a stage.

View File

@ -712,6 +712,9 @@ swf_tests! {
(as3_propertyisenumerable_namespaces, "avm2/propertyisenumerable_namespaces", 1),
(as3_interface_namespaces, "avm2/interface_namespaces", 1),
(as3_interactiveobject_enabled, "avm2/interactiveobject_enabled", 1),
(as3_stage_mouseenabled, "avm2/stage_mouseenabled", 1),
(as3_simplebutton_mouseenabled, "avm2/simplebutton_mouseenabled", 1),
(as3_edittext_mouseenabled, "avm2/edittext_mouseenabled", 1),
}
// TODO: These tests have some inaccuracies currently, so we use approx_eq to test that numeric values are close enough.

View File

@ -0,0 +1,54 @@
package {
public class Test {
}
}
import flash.text.TextField;
trace("///var text = new TextField();");
var text = new TextField();
trace("///(Initial state of event enabled flags...)");
trace("///text.mouseEnabled");
trace(text.mouseEnabled);
trace("///text.doubleClickEnabled");
trace(text.doubleClickEnabled);
trace("///text.doubleClickEnabled = true");
text.doubleClickEnabled = true;
trace("///text.mouseEnabled");
trace(text.mouseEnabled);
trace("///text.doubleClickEnabled");
trace(text.doubleClickEnabled);
trace("///text.mouseEnabled = false");
text.mouseEnabled = false;
trace("///text.mouseEnabled");
trace(text.mouseEnabled);
trace("///text.doubleClickEnabled");
trace(text.doubleClickEnabled);
trace("///text.doubleClickEnabled = false");
text.doubleClickEnabled = false;
trace("///text.mouseEnabled");
trace(text.mouseEnabled);
trace("///text.doubleClickEnabled");
trace(text.doubleClickEnabled);
trace("///text.mouseEnabled = true");
text.mouseEnabled = true;
trace("///text.mouseEnabled");
trace(text.mouseEnabled);
trace("///text.doubleClickEnabled");
trace(text.doubleClickEnabled);

View File

@ -0,0 +1,26 @@
///var text = new TextField();
///(Initial state of event enabled flags...)
///text.mouseEnabled
true
///text.doubleClickEnabled
false
///text.doubleClickEnabled = true
///text.mouseEnabled
true
///text.doubleClickEnabled
true
///text.mouseEnabled = false
///text.mouseEnabled
false
///text.doubleClickEnabled
true
///text.doubleClickEnabled = false
///text.mouseEnabled
false
///text.doubleClickEnabled
false
///text.mouseEnabled = true
///text.mouseEnabled
true
///text.doubleClickEnabled
false

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,54 @@
package {
public class Test {
}
}
import flash.display.SimpleButton;
trace("///var btn = new SimpleButton();");
var btn = new SimpleButton();
trace("///(Initial state of event enabled flags...)");
trace("///btn.mouseEnabled");
trace(btn.mouseEnabled);
trace("///btn.doubleClickEnabled");
trace(btn.doubleClickEnabled);
trace("///btn.doubleClickEnabled = true");
btn.doubleClickEnabled = true;
trace("///btn.mouseEnabled");
trace(btn.mouseEnabled);
trace("///btn.doubleClickEnabled");
trace(btn.doubleClickEnabled);
trace("///btn.mouseEnabled = false");
btn.mouseEnabled = false;
trace("///btn.mouseEnabled");
trace(btn.mouseEnabled);
trace("///btn.doubleClickEnabled");
trace(btn.doubleClickEnabled);
trace("///btn.doubleClickEnabled = false");
btn.doubleClickEnabled = false;
trace("///btn.mouseEnabled");
trace(btn.mouseEnabled);
trace("///btn.doubleClickEnabled");
trace(btn.doubleClickEnabled);
trace("///btn.mouseEnabled = true");
btn.mouseEnabled = true;
trace("///btn.mouseEnabled");
trace(btn.mouseEnabled);
trace("///btn.doubleClickEnabled");
trace(btn.doubleClickEnabled);

View File

@ -0,0 +1,26 @@
///var btn = new SimpleButton();
///(Initial state of event enabled flags...)
///btn.mouseEnabled
true
///btn.doubleClickEnabled
false
///btn.doubleClickEnabled = true
///btn.mouseEnabled
true
///btn.doubleClickEnabled
true
///btn.mouseEnabled = false
///btn.mouseEnabled
false
///btn.doubleClickEnabled
true
///btn.doubleClickEnabled = false
///btn.mouseEnabled
false
///btn.doubleClickEnabled
false
///btn.mouseEnabled = true
///btn.mouseEnabled
true
///btn.doubleClickEnabled
false

View File

@ -0,0 +1,15 @@
///(Initial state of event enabled flags...)
///this.stage.mouseEnabled
true
///this.stage.doubleClickEnabled
false
///this.stage.doubleClickEnabled = true
///this.stage.mouseEnabled
true
///this.stage.doubleClickEnabled
true
///this.stage.doubleClickEnabled = false
///this.stage.mouseEnabled
true
///this.stage.doubleClickEnabled
false

Binary file not shown.

Binary file not shown.