avm2: Migrate ContextMenu-related classes to AS

This commit is contained in:
Adrian Wielgosik 2022-07-17 12:34:34 +02:00 committed by Mike Welsh
parent cad3cd8dbf
commit 22d2810ef9
14 changed files with 90 additions and 303 deletions

View File

@ -87,8 +87,6 @@ pub struct SystemClasses<'gc> {
pub date: ClassObject<'gc>,
pub qname: ClassObject<'gc>,
pub sharedobject: ClassObject<'gc>,
pub nativemenu: ClassObject<'gc>,
pub contextmenu: ClassObject<'gc>,
pub mouseevent: ClassObject<'gc>,
pub textevent: ClassObject<'gc>,
pub errorevent: ClassObject<'gc>,
@ -151,8 +149,6 @@ impl<'gc> SystemClasses<'gc> {
date: object,
qname: object,
sharedobject: object,
nativemenu: object,
contextmenu: object,
mouseevent: object,
textevent: object,
errorevent: object,
@ -658,17 +654,6 @@ pub fn load_player_globals<'gc>(
flash::display::bitmapdata::create_class(mc),
script
);
avm2_system_class!(
nativemenu,
activation,
flash::display::nativemenu::create_class(mc),
script
);
class(
activation,
flash::display::nativemenuitem::create_class(mc),
script,
)?;
// package `flash.filters`
class(
@ -716,17 +701,6 @@ pub fn load_player_globals<'gc>(
);
// package `flash.ui`
avm2_system_class!(
contextmenu,
activation,
flash::ui::contextmenu::create_class(mc),
script
);
class(
activation,
flash::ui::contextmenuitem::create_class(mc),
script,
)?;
class(activation, flash::ui::mouse::create_class(mc), script)?;
class(activation, flash::ui::keyboard::create_class(mc), script)?;

View File

@ -11,8 +11,6 @@ pub mod interactiveobject;
pub mod loader;
pub mod loaderinfo;
pub mod movieclip;
pub mod nativemenu;
pub mod nativemenuitem;
pub mod shape;
pub mod simplebutton;
pub mod sprite;

View File

@ -0,0 +1,6 @@
package flash.display {
import flash.events.EventDispatcher;
public class NativeMenu extends EventDispatcher {
}
}

View File

@ -0,0 +1,6 @@
package flash.display {
import flash.events.EventDispatcher;
public class NativeMenuItem extends EventDispatcher {
public var enabled: Boolean;
}
}

View File

@ -141,7 +141,8 @@ fn set_context_menu<'gc>(
.and_then(|t| t.as_display_object())
.and_then(|dobj| dobj.as_interactive())
{
let cls = activation.avm2().classes().nativemenu;
let cls_name = QName::new(Namespace::package("flash.display"), "NativeMenu");
let cls = activation.resolve_class(&cls_name.into())?;
let value = args
.get(0)
.cloned()

View File

@ -1,46 +0,0 @@
//! `flash.display.NativeMenu` builtin/prototype
use crate::avm2::activation::Activation;
use crate::avm2::class::{Class, ClassAttributes};
use crate::avm2::method::Method;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::Object;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::{GcCell, MutationContext};
fn instance_init<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
if let Some(this) = this {
activation.super_init(this, &[])?;
}
Ok(Value::Undefined)
}
fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Construct `NativeMenu`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
let class = Class::new(
QName::new(Namespace::package("flash.display"), "NativeMenu"),
Some(QName::new(Namespace::package("flash.events"), "EventDispatcher").into()),
Method::from_builtin(instance_init, "<NativeMenu instance initializer>", mc),
Method::from_builtin(class_init, "<NativeMenu class initializer>", mc),
mc,
);
let mut write = class.write(mc);
write.set_attributes(ClassAttributes::SEALED);
class
}

View File

@ -1,49 +0,0 @@
//! `flash.display.NativeMenuItem` builtin/prototype
use crate::avm2::activation::Activation;
use crate::avm2::class::{Class, ClassAttributes};
use crate::avm2::method::Method;
use crate::avm2::names::{Namespace, QName};
use crate::avm2::object::Object;
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::{GcCell, MutationContext};
fn instance_init<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
if let Some(this) = this {
activation.super_init(this, &[])?;
}
Ok(Value::Undefined)
}
fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Construct `NativeMenuItem`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
let class = Class::new(
QName::new(Namespace::package("flash.display"), "NativeMenuItem"),
Some(QName::new(Namespace::package("flash.events"), "EventDispatcher").into()),
Method::from_builtin(instance_init, "<NativeMenuItem instance initializer>", mc),
Method::from_builtin(class_init, "<NativeMenuItem class initializer>", mc),
mc,
);
let mut write = class.write(mc);
write.set_attributes(ClassAttributes::SEALED);
const PUBLIC_INSTANCE_SLOTS: &[(&str, &str, &str)] = &[("enabled", "", "Boolean")];
write.define_public_slot_instance_traits(PUBLIC_INSTANCE_SLOTS);
class
}

View File

@ -1,6 +1,5 @@
//! `flash.ui` namespace
pub mod contextmenu;
pub mod contextmenuitem;
pub mod context_menu;
pub mod keyboard;
pub mod mouse;

View File

@ -0,0 +1,23 @@
package flash.ui
{
import flash.display.NativeMenu;
public final class ContextMenu extends NativeMenu
{
public function ContextMenu()
{
super();
this.customItems = new Array();
}
public var customItems: Array;
public native function hideBuiltInItems(): void;
public static function get isSupported() : Boolean
{
// TODO: return true when implementation actually affects the context menu
return false;
}
}
}

View File

@ -0,0 +1,29 @@
package flash.ui
{
import flash.display.NativeMenuItem;
public final class ContextMenuItem extends NativeMenuItem
{
public function ContextMenuItem(
caption:String,
separatorBefore:Boolean = false,
enabled:Boolean = true,
visible:Boolean = true
)
{
this.caption = caption;
this.separatorBefore = separatorBefore;
this.enabled = enabled;
this.visible = visible;
}
public function clone(): ContextMenuItem
{
return new ContextMenuItem(this.caption, this.separatorBefore, this.enabled, this.visible);
}
public var caption: String;
public var separatorBefore: Boolean;
public var visible: Boolean;
}
}

View File

@ -0,0 +1,19 @@
use crate::avm2::activation::Activation;
use crate::avm2::object::Object;
use crate::avm2::value::Value;
use crate::avm2::Error;
pub fn hide_built_in_items<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
// TODO: replace this by a proper implementation.
log::warn!("flash.ui.ContextMenu is a stub");
activation
.context
.stage
.set_show_menu(&mut activation.context, false);
Ok(Value::Undefined)
}

View File

@ -1,90 +0,0 @@
//! `flash.ui.ContextMenu` builtin/prototype
use crate::avm2::activation::Activation;
use crate::avm2::class::{Class, ClassAttributes};
use crate::avm2::method::{Method, NativeMethodImpl};
use crate::avm2::names::{Multiname, Namespace, QName};
use crate::avm2::object::{Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::ArrayObject;
use crate::avm2::Error;
use gc_arena::{GcCell, MutationContext};
fn instance_init<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
if let Some(mut this) = this {
log::warn!("flash.ui.ContextMenu is a stub");
activation.super_init(this, &[])?;
this.set_property(
&Multiname::public("customItems"),
ArrayObject::empty(activation).unwrap().into(),
activation,
)?;
}
Ok(Value::Undefined)
}
fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
fn hide_built_in_items<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
// TODO: replace this by a proper implementation.
log::warn!("flash.ui.ContextMenu is a stub");
activation
.context
.stage
.set_show_menu(&mut activation.context, false);
Ok(Value::Undefined)
}
fn is_supported<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
// TODO: return true when replaced by proper implementation
Ok(false.into())
}
/// Construct `ContextMenu`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
let class = Class::new(
QName::new(Namespace::package("flash.ui"), "ContextMenu"),
Some(QName::new(Namespace::package("flash.display"), "NativeMenu").into()),
Method::from_builtin(instance_init, "<ContextMenu instance initializer>", mc),
Method::from_builtin(class_init, "<ContextMenu class initializer>", mc),
mc,
);
let mut write = class.write(mc);
write.set_attributes(ClassAttributes::SEALED | ClassAttributes::FINAL);
const PUBLIC_CLASS_PROPERTIES: &[(&str, Option<NativeMethodImpl>, Option<NativeMethodImpl>)] =
&[("isSupported", Some(is_supported), None)];
write.define_public_builtin_class_properties(mc, PUBLIC_CLASS_PROPERTIES);
const PUBLIC_INSTANCE_METHODS: &[(&str, NativeMethodImpl)] =
&[("hideBuiltInItems", hide_built_in_items)];
write.define_public_builtin_instance_methods(mc, PUBLIC_INSTANCE_METHODS);
const PUBLIC_INSTANCE_SLOTS: &[(&str, &str, &str)] = &[("customItems", "", "Array")];
write.define_public_slot_instance_traits(PUBLIC_INSTANCE_SLOTS);
class
}

View File

@ -1,87 +0,0 @@
//! `flash.ui.ContextMenuItem` builtin/prototype
use crate::avm2::activation::Activation;
use crate::avm2::class::{Class, ClassAttributes};
use crate::avm2::method::Method;
use crate::avm2::names::{Multiname, Namespace, QName};
use crate::avm2::object::{Object, TObject};
use crate::avm2::value::Value;
use crate::avm2::Error;
use gc_arena::{GcCell, MutationContext};
fn instance_init<'gc>(
activation: &mut Activation<'_, 'gc, '_>,
this: Option<Object<'gc>>,
args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
if let Some(mut this) = this {
// note: this doesn't propagate arguments to NativeMenuItem correctly
activation.super_init(this, &[])?;
// TODO: would be nice to refactor this if we could easily automate default values
let caption = if let Some(arg) = args.get(0) {
arg.coerce_to_string(activation)?
} else {
// ideally argument validation should not let us call with 0 args
return Ok(Value::Undefined);
};
let separator = if let Some(separator) = args.get(1) {
separator.coerce_to_boolean()
} else {
false
};
let enabled = if let Some(enabled) = args.get(2) {
enabled.coerce_to_boolean()
} else {
true
};
let visible = if let Some(visible) = args.get(3) {
visible.coerce_to_boolean()
} else {
true
};
this.set_property(&Multiname::public("caption"), caption.into(), activation)?;
this.set_property(
&Multiname::public("separatorBefore"),
separator.into(),
activation,
)?;
this.set_property(&Multiname::public("enabled"), enabled.into(), activation)?;
this.set_property(&Multiname::public("visible"), visible.into(), activation)?;
}
Ok(Value::Undefined)
}
fn class_init<'gc>(
_activation: &mut Activation<'_, 'gc, '_>,
_this: Option<Object<'gc>>,
_args: &[Value<'gc>],
) -> Result<Value<'gc>, Error> {
Ok(Value::Undefined)
}
/// Construct `ContextMenuItem`'s class.
pub fn create_class<'gc>(mc: MutationContext<'gc, '_>) -> GcCell<'gc, Class<'gc>> {
let class = Class::new(
QName::new(Namespace::package("flash.ui"), "ContextMenuItem"),
Some(QName::new(Namespace::package("flash.display"), "NativeMenuItem").into()),
Method::from_builtin(instance_init, "<ContextMenuItem instance initializer>", mc),
Method::from_builtin(class_init, "<ContextMenuItem class initializer>", mc),
mc,
);
let mut write = class.write(mc);
write.set_attributes(ClassAttributes::SEALED | ClassAttributes::FINAL);
const PUBLIC_INSTANCE_SLOTS: &[(&str, &str, &str)] = &[
("caption", "", "String"),
("separatorBefore", "", "Boolean"),
("visible", "", "Boolean"),
];
write.define_public_slot_instance_traits(PUBLIC_INSTANCE_SLOTS);
class
}

View File

@ -16,6 +16,8 @@ include "flash/display/JointStyle.as"
include "flash/display/JPEGEncoderOptions.as"
include "flash/display/JPEGXREncoderOptions.as"
include "flash/display/LineScaleMode.as"
include "flash/display/NativeMenu.as"
include "flash/display/NativeMenuItem.as"
include "flash/display/PixelSnapping.as"
include "flash/display/PNGEncoderOptions.as"
include "flash/display/Scene.as"
@ -52,6 +54,8 @@ include "flash/text/TextFieldType.as"
include "flash/text/TextFormatAlign.as"
include "flash/text/TextInteractionMode.as"
include "flash/text/TextLineMetrics.as"
include "flash/ui/ContextMenu.as"
include "flash/ui/ContextMenuItem.as"
include "flash/utils.as"
include "flash/utils/CompressionAlgorithm.as"
include "flash/utils/Endian.as"