core: Add `InteractiveObject` trait for objects that can receive input events
This commit is contained in:
parent
89718475df
commit
618c32f859
|
@ -29,6 +29,7 @@ mod bitmap;
|
|||
mod container;
|
||||
mod edit_text;
|
||||
mod graphic;
|
||||
mod interactive;
|
||||
mod morph_shape;
|
||||
mod movie_clip;
|
||||
mod stage;
|
||||
|
@ -46,6 +47,7 @@ pub use avm2_button::Avm2Button;
|
|||
pub use bitmap::Bitmap;
|
||||
pub use edit_text::{AutoSizeMode, EditText, TextSelection};
|
||||
pub use graphic::Graphic;
|
||||
pub use interactive::{InteractiveObject, TInteractiveObject};
|
||||
pub use morph_shape::{MorphShape, MorphShapeStatic};
|
||||
pub use movie_clip::{MovieClip, Scene};
|
||||
pub use stage::{Stage, StageAlign, StageQuality, StageScaleMode};
|
||||
|
@ -1077,6 +1079,9 @@ pub trait TDisplayObject<'gc>:
|
|||
fn as_bitmap(self) -> Option<Bitmap<'gc>> {
|
||||
None
|
||||
}
|
||||
fn as_interactive(self) -> Option<InteractiveObject<'gc>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn apply_place_object(
|
||||
&self,
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
//! Interactive object enumtrait
|
||||
|
||||
use crate::display_object::movie_clip::MovieClip;
|
||||
use bitflags::bitflags;
|
||||
use gc_arena::{Collect, MutationContext};
|
||||
use ruffle_macros::enum_trait_object;
|
||||
use std::cell::{Ref, RefMut};
|
||||
use std::fmt::Debug;
|
||||
|
||||
bitflags! {
|
||||
/// Boolean state flags used by `InteractiveObject`.
|
||||
#[derive(Collect)]
|
||||
#[collect(require_static)]
|
||||
struct InteractiveObjectFlags: u8 {
|
||||
/// Whether this `InteractiveObject` accepts mouse and other user
|
||||
/// events.
|
||||
const MOUSE_ENABLED = 1 << 0;
|
||||
|
||||
/// Whether this `InteractiveObject` accepts double-clicks.
|
||||
const DOUBLE_CLICK_ENABLED = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Collect, Clone, Debug)]
|
||||
#[collect(no_drop)]
|
||||
pub struct InteractiveObjectBase {
|
||||
flags: InteractiveObjectFlags,
|
||||
}
|
||||
|
||||
impl Default for InteractiveObjectBase {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
flags: InteractiveObjectFlags::MOUSE_ENABLED,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[enum_trait_object(
|
||||
#[derive(Clone, Collect, Debug, Copy)]
|
||||
#[collect(no_drop)]
|
||||
pub enum InteractiveObject<'gc> {
|
||||
MovieClip(MovieClip<'gc>),
|
||||
}
|
||||
)]
|
||||
pub trait TInteractiveObject<'gc>:
|
||||
'gc + Clone + Copy + Collect + Debug + Into<InteractiveObject<'gc>>
|
||||
{
|
||||
fn base(&self) -> Ref<InteractiveObjectBase>;
|
||||
|
||||
fn base_mut(&self, mc: MutationContext<'gc, '_>) -> RefMut<InteractiveObjectBase>;
|
||||
|
||||
/// Check if the interactive object accepts user input.
|
||||
fn mouse_enabled(self) -> bool {
|
||||
self.base()
|
||||
.flags
|
||||
.contains(InteractiveObjectFlags::MOUSE_ENABLED)
|
||||
}
|
||||
|
||||
/// Set if the interactive object accepts user input.
|
||||
fn set_mouse_enabled(self, mc: MutationContext<'gc, '_>, value: bool) {
|
||||
self.base_mut(mc)
|
||||
.flags
|
||||
.set(InteractiveObjectFlags::MOUSE_ENABLED, value)
|
||||
}
|
||||
|
||||
/// Check if the interactive object accepts double-click events.
|
||||
fn double_click_enabled(self) -> bool {
|
||||
self.base()
|
||||
.flags
|
||||
.contains(InteractiveObjectFlags::DOUBLE_CLICK_ENABLED)
|
||||
}
|
||||
|
||||
// Set if the interactive object accepts double-click events.
|
||||
fn set_double_click_enabled(self, mc: MutationContext<'gc, '_>, value: bool) {
|
||||
self.base_mut(mc)
|
||||
.flags
|
||||
.set(InteractiveObjectFlags::DOUBLE_CLICK_ENABLED, value)
|
||||
}
|
||||
}
|
|
@ -20,6 +20,9 @@ use crate::display_object::container::{
|
|||
dispatch_added_event_only, dispatch_added_to_stage_event_only, dispatch_removed_event,
|
||||
ChildContainer, TDisplayObjectContainer,
|
||||
};
|
||||
use crate::display_object::interactive::{
|
||||
InteractiveObject, InteractiveObjectBase, TInteractiveObject,
|
||||
};
|
||||
use crate::display_object::{
|
||||
Avm1Button, Avm2Button, Bitmap, DisplayObjectBase, EditText, Graphic, MorphShapeStatic,
|
||||
TDisplayObject, Text, Video,
|
||||
|
@ -68,6 +71,7 @@ pub struct MovieClip<'gc>(GcCell<'gc, MovieClipData<'gc>>);
|
|||
#[collect(no_drop)]
|
||||
pub struct MovieClipData<'gc> {
|
||||
base: DisplayObjectBase<'gc>,
|
||||
interactive_base: InteractiveObjectBase,
|
||||
static_data: Gc<'gc, MovieClipStatic>,
|
||||
tag_stream_pos: u64,
|
||||
current_frame: FrameNumber,
|
||||
|
@ -98,6 +102,7 @@ impl<'gc> MovieClip<'gc> {
|
|||
gc_context,
|
||||
MovieClipData {
|
||||
base: Default::default(),
|
||||
interactive_base: Default::default(),
|
||||
static_data: Gc::allocate(gc_context, MovieClipStatic::empty(movie)),
|
||||
tag_stream_pos: 0,
|
||||
current_frame: 0,
|
||||
|
@ -132,6 +137,7 @@ impl<'gc> MovieClip<'gc> {
|
|||
gc_context,
|
||||
MovieClipData {
|
||||
base: Default::default(),
|
||||
interactive_base: Default::default(),
|
||||
static_data: Gc::allocate(gc_context, MovieClipStatic::empty(movie)),
|
||||
tag_stream_pos: 0,
|
||||
current_frame: 0,
|
||||
|
@ -166,6 +172,7 @@ impl<'gc> MovieClip<'gc> {
|
|||
gc_context,
|
||||
MovieClipData {
|
||||
base: Default::default(),
|
||||
interactive_base: Default::default(),
|
||||
static_data: Gc::allocate(
|
||||
gc_context,
|
||||
MovieClipStatic::with_data(id, swf, num_frames),
|
||||
|
@ -200,6 +207,7 @@ impl<'gc> MovieClip<'gc> {
|
|||
gc_context,
|
||||
MovieClipData {
|
||||
base: Default::default(),
|
||||
interactive_base: Default::default(),
|
||||
static_data: Gc::allocate(
|
||||
gc_context,
|
||||
MovieClipStatic::with_data(0, movie.into(), num_frames),
|
||||
|
@ -2029,6 +2037,10 @@ impl<'gc> TDisplayObject<'gc> for MovieClip<'gc> {
|
|||
Some(self.into())
|
||||
}
|
||||
|
||||
fn as_interactive(self) -> Option<InteractiveObject<'gc>> {
|
||||
Some(self.into())
|
||||
}
|
||||
|
||||
fn as_drawing(&self, gc_context: MutationContext<'gc, '_>) -> Option<RefMut<'_, Drawing>> {
|
||||
Some(RefMut::map(self.0.write(gc_context), |s| &mut s.drawing))
|
||||
}
|
||||
|
@ -2129,6 +2141,16 @@ impl<'gc> TDisplayObjectContainer<'gc> for MovieClip<'gc> {
|
|||
impl_display_object_container!(container);
|
||||
}
|
||||
|
||||
impl<'gc> TInteractiveObject<'gc> for MovieClip<'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> MovieClipData<'gc> {
|
||||
/// Replace the current MovieClipData with a completely new SwfMovie.
|
||||
///
|
||||
|
|
Loading…
Reference in New Issue