core: `Stage`, `EditText`, and `Avm2Button` should also be interactive objects.
This commit is contained in:
parent
e71c749db5
commit
95f105aadd
|
@ -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,
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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>:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
|
@ -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.
|
@ -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);
|
|
@ -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
|
Binary file not shown.
Binary file not shown.
|
@ -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.
Loading…
Reference in New Issue